MQTT 3.1.1 became an OASIS standard in 2014 and later an ISO standard (ISO/IEC 20922). MQTT 5 followed as an OASIS standard in 2019. The core model — publish/subscribe over topics with three QoS levels — is unchanged, but MQTT 5 adds the features people kept building workarounds for: proper error reporting, expiry, metadata, load-balanced subscriptions and flow control. Here is what actually differs and when it matters.
Summary table
| Feature | MQTT 3.1.1 | MQTT 5 |
|---|---|---|
| Error reporting | 6 CONNACK codes, SUBACK failure only | Reason codes on all acks, plus reason strings |
| Server-initiated disconnect | Socket just closes | DISCONNECT with a reason code |
| Session lifetime | Clean Session flag (on/off) | Clean Start + Session Expiry Interval |
| Message expiry | No | Message Expiry Interval |
| Custom metadata | Only inside the payload | User properties |
| Shared subscriptions | Broker-specific extensions | Standard $share/group/filter |
| Topic aliases | No | Yes |
| Request/response | Convention only | Response Topic + Correlation Data |
| Flow control | No | Receive Maximum, Maximum Packet Size |
| Authentication | Username/password | Plus enhanced auth via AUTH packet |
Reason codes everywhere
In 3.1.1, a failed CONNECT returns one of six codes, and most other failures are silent: if a publish is not authorized, the broker may just drop it or close the connection. MQTT 5 adds a reason code to CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK, DISCONNECT and AUTH, optionally with a human-readable reason string. The broker can also send DISCONNECT to explain why it closes a connection, such as 0x8E Session taken over. The full list of common codes is in our MQTT connection errors guide.
Session expiry and message expiry
Session Expiry Interval
MQTT 3.1.1 offers one switch: Clean Session. With cleanSession=false the broker keeps your subscriptions and queued messages forever, which can pile up for devices that never return. MQTT 5 splits this into Clean Start (discard any existing session on connect?) and Session Expiry Interval (how many seconds to keep the session after disconnecting). A device can now say: keep my session for one hour, then clean up.
Message Expiry Interval
A publisher can set a lifetime in seconds on each message. If it has not been delivered by then — for example because the subscriber was offline — the broker discards it. This prevents an offline actuator from receiving a stale command hours later, and it also applies to retained messages.
User properties and content metadata
MQTT 5 packets can carry user properties: arbitrary UTF-8 key/value pairs, similar to HTTP headers. Use them for trace IDs, schema versions or source identifiers without wrapping the payload in an envelope. Two related properties describe the payload itself: Payload Format Indicator (binary or UTF-8) and Content Type (for example application/json).
client.publish('factory/line-1/temp', JSON.stringify({ c: 21.4 }), {
qos: 1,
properties: {
messageExpiryInterval: 60,
contentType: 'application/json',
userProperties: { traceId: 'a1b2c3', schema: 'v2' },
},
});Shared subscriptions
Normally every subscriber receives every matching message. A shared subscription distributes messages across a group instead, so you can scale a backend horizontally. Subscribe to $share/workers/orders/# from three instances and each message goes to only one of them. Several 3.1.1 brokers offered this as a proprietary extension; MQTT 5 standardizes the syntax. Learn more about filters in MQTT topics and wildcards.
Topic aliases
Long topic names are sent with every publish. With topic aliases, a client maps a topic to a small integer once and then sends only the integer. Each side announces how many aliases it accepts via Topic Alias Maximum. This saves bandwidth for devices that publish frequently to long topics over metered links.
Request/response
MQTT is one-way by design, but many applications need replies. MQTT 5 adds a Response Topic (where to send the answer) and Correlation Data (which request the answer belongs to) to the publish packet. A responder reads both and publishes its reply accordingly, so you no longer have to invent your own envelope format.
Flow control and limits
- Receive Maximum: how many unacknowledged QoS 1 and QoS 2 messages a side is willing to handle at once. It stops a fast broker from overwhelming a slow device. See MQTT QoS levels.
- Maximum Packet Size: each side can refuse packets above a size it declares.
- Server Keep Alive: the broker can override the client's keep-alive value.
- Assigned Client Identifier: if you connect with an empty client ID, the broker tells you the one it generated.
Enhanced authentication
MQTT 3.1.1 authentication is limited to a username and password in CONNECT (plus TLS client certificates at the transport level). MQTT 5 adds an AUTH packet and the Authentication Method and Authentication Data properties, enabling challenge/response schemes such as SCRAM or Kerberos, and re-authentication on a live connection without disconnecting. Broker support varies, so check before you rely on it.
Smaller but useful additions
- Subscription options: No Local (do not echo my own messages), Retain As Published and Retain Handling.
- Subscription identifiers: tell which subscription matched a delivered message.
- Will Delay Interval: delay the Last Will so a quick reconnect does not trigger it.
Should you upgrade?
For new projects, default to MQTT 5: better errors alone save hours of debugging. Keep 3.1.1 where firmware or libraries cannot be updated; nothing forces a migration, and both versions coexist on the same broker. When you upgrade, enable the version in your client (for MQTT.js, protocolVersion: 5) and verify the broker accepts it.
Connect with MQTT 5 in the browser
New to the protocol overall? Start with what is MQTT, or try both versions right now in the online MQTT client.
Frequently asked questions
Is MQTT 5 backward compatible with MQTT 3.1.1?
Not on the wire: the packet formats differ and the protocol level byte is 5 instead of 4. In practice most brokers support both versions at the same time, so MQTT 3.1.1 and MQTT 5 clients can exchange messages through the same broker.
Should I use MQTT 5 or 3.1.1 for a new project?
Use MQTT 5 when both your broker and client libraries support it, which is true for most current options. Stay on 3.1.1 for constrained or legacy devices whose firmware or libraries only implement that version.
What happened to MQTT 4?
There is no MQTT 4. Version 3.1.1 uses protocol level 4 in the CONNECT packet, so the next version was numbered 5 to match its protocol level and avoid confusion.