Skip to main content
Part of: IoT Protocols & Standards
Protocols · 6 min read

MQTT 5 Features Worth Adopting in 2026

The MQTT 5 features that earn their keep on real IoT products — flow control, message expiry, shared subscriptions, reason codes, and the upgrade story from 3.1.1.

MQTT 5 has been the standard since 2019 but a surprising number of IoT products still ship MQTT 3.1.1. Some features in the upgrade are nice-to-have; a few genuinely change the operational story. Here is what we use on real projects, and the migration path from 3.1.1 if you’re still there.

Reason codes — the boring win that pays back fastest

In MQTT 3.1.1, a connection failure returned one of five generic codes. Debugging a flaky deployment was guesswork.

MQTT 5 returns specific reason codes for every protocol operation: Bad Username or Password, Not Authorized, Server Busy, Banned, Quota Exceeded, Payload Format Invalid, and many more. Same for publish, subscribe, disconnect.

Why this matters: when 1% of devices intermittently fail to connect, you can finally tell why without packet captures. Implementations that adopted MQTT 5 reason codes typically resolve connection-class incidents in hours rather than days.

This is the single most impactful upgrade for operations.

Properties — the protocol got extensible

MQTT 5 added a properties bag to almost every packet. Standard properties include Content-Type, Response-Topic, Correlation-Data, User-Property, Message-Expiry-Interval. Brokers and clients can also send custom user properties.

Practical uses we deploy:

  • Content-Type: application/cbor so consumers know the payload encoding without out-of-band agreement
  • Response-Topic for request/reply patterns over MQTT (cleaner than re-implementing the pattern manually)
  • User-Property for tracing — propagating trace IDs through MQTT for distributed-tracing visibility (see our fleet observability post)

Properties also future-proof the protocol. Older brokers ignore unknown properties; newer ones use them. The graceful-degradation story is real.

Message expiry interval — the “don’t deliver stale data” feature

A device sends a temperature reading. The MQTT broker holds it because the consumer is offline. The consumer comes back five minutes later. With 3.1.1, the broker delivers the now-stale reading.

In MQTT 5, the publisher can set Message-Expiry-Interval (in seconds). Brokers drop expired messages without delivering them.

Use cases:

  • Real-time sensor data where stale readings would mislead operators
  • Command messages that have a deadline (“turn on within 30 seconds or skip”)
  • Alerts that are no longer actionable after a window

Cost: each retained or queued message has a small overhead. At fleet scale, dropping expired messages reduces broker memory pressure measurably.

Shared subscriptions — horizontal scaling done right

MQTT 3.1.1 had no built-in load balancing for consumers. To scale a consumer, you either ran one instance with all the throughput it could handle, or implemented some form of partitioning manually.

MQTT 5 introduces shared subscriptions: subscribe to $share/group/topic and the broker round-robins messages across all subscribers in the group. Add a consumer to scale; remove a consumer to scale down.

This is the right pattern for any consumer-side service that processes IoT messages — analytics ingestors, ERP integrations, alerting services. Each service gets its own group; multiple instances of one service share within the group.

Without shared subscriptions you end up writing your own consumer-side coordinator. Don’t bother — use the protocol feature.

Flow control / receive maximum — backpressure that works

When a slow consumer subscribes to a fire-hose topic, MQTT 3.1.1 had no clean backpressure mechanism. The broker buffered, and at some point, things broke.

MQTT 5 adds Receive-Maximum to CONNECT — the client tells the broker how many in-flight messages it can handle. The broker pauses sending when the limit is reached and resumes as the client acks.

Practical effect: misbehaving or slow consumers no longer cause broker memory blow-ups. The slowness propagates back to the producer in a controlled way.

Other features worth knowing

  • Subscription identifier — the broker tags delivered messages with the subscription ID that matched, useful when one client has overlapping topic filters
  • Topic alias — replace long topic strings with short integers after the first message; tiny bandwidth savings at high message rates
  • Server reference / Server keep alive — the broker can redirect clients during scaling events or rolling deployments
  • Reason string — human-readable text accompanying reason codes; goes straight into your logs

Migration from 3.1.1

If you’re on 3.1.1 today, the migration is relatively painless:

  1. Verify your broker supports MQTT 5. Most modern brokers (EMQX, HiveMQ, AWS IoT Core, Azure IoT Hub since 2022, Mosquitto since 2.0) support both versions concurrently.

  2. Update client libraries. Eclipse Paho, Mosquitto client, AWS SDK, Azure SDK all support MQTT 5. Library upgrade is usually a one-line config change in the connection options.

  3. Adopt features incrementally. Start with reason codes (free win for ops). Add properties for tracing next. Then message expiry, shared subscriptions, flow control as use cases justify.

  4. Test with both versions. During migration, brokers see both 3.1.1 and 5 clients. Test that the message routing and topic structure works under both.

The migration usually fits within a single release cycle. The win is durable — better operability for the life of the product.

When 3.1.1 still makes sense

Two cases:

  • Devices on extremely constrained MCUs where the slightly larger MQTT 5 client library doesn’t fit
  • Existing fleets where the cost of OTA-updating millions of devices to a new MQTT version doesn’t pay back

For new deployments in 2026, MQTT 5 is the default. There is no reason to start a project on 3.1.1.

What we typically ship

  • Broker: EMQX (or AWS IoT Core / Azure IoT Hub if managed) configured for MQTT 5 with 3.1.1 fallback for legacy devices
  • Clients: MQTT 5 from day one; reason codes logged; trace IDs propagated via user properties
  • Backpressure: receive-maximum configured per consumer class
  • Consumer scaling: shared subscriptions for every consumer service
  • Message expiry: set on telemetry where staleness changes meaning

If you are evaluating an MQTT 5 migration or starting a new IoT product on 3.1.1, we have shipped both.

By Diglogic Engineering · May 9, 2026

Share

Ready to ship

Let's get started.

Tell us about the problem. We come back within one business day with a clear path, a timeline you can plan around, and a fixed-scope first milestone.