The MQTT Reason Codes Reference is a searchable lookup for the single-byte reason codes introduced in MQTT 5.0. Unlike MQTT 3.1.1, which had only five CONNACK return codes and no reason codes elsewhere, version 5.0 uses a unified reason-code byte across nearly every acknowledgement packet plus DISCONNECT and AUTH — so the same 0x87 can explain a refused connect, a blocked publish, or a denied subscribe, all in one consistent system.
How MQTT 5.0 reason codes differ from 3.1.1
In MQTT 3.1.1, the only server-to-client feedback on success or failure was the CONNACK return code (0–5). If a PUBLISH was rejected, if a SUBSCRIBE was denied, or if the broker closed the connection, the client received almost no diagnostic information. MQTT 5.0 fixed this comprehensively: every acknowledgement carries a reason code, and reason strings (human-readable text) and user properties can accompany them. Debugging MQTT 5.0 sessions is dramatically easier than 3.1.1.
The range split
Every MQTT 5.0 control packet that reports a result carries one byte:
0x00 – 0x7F Success / normal operation / informational
0x80 – 0xFF Error / refusal / failure
This split is consistent across all packet types. If the high bit is set, something went wrong. If not, the operation completed (though the specific success meaning varies by packet type — see below).
Packets that carry reason codes
| Packet | Carries reason code |
|---|---|
| CONNACK | Yes — connection accepted or rejected |
| PUBACK, PUBREC, PUBREL, PUBCOMP | Yes — QoS 1 and QoS 2 acknowledgement chain |
| SUBACK | Yes — per-subscription grant or failure |
| UNSUBACK | Yes — per-unsubscription result |
| DISCONNECT | Yes — now bidirectional (broker can disconnect client with reason) |
| AUTH | Yes — used in extended authentication flows |
Same code, different labels by packet
0x00 always means success, but the human-readable label is packet-dependent:
- In
CONNACKandPUBACK: Success - In
SUBACK: Granted QoS 0 (the subscription was accepted at QoS 0) - In
DISCONNECT: Normal disconnection
This is expected behavior, not an inconsistency — the code is the same, but what “success” means depends on what was being acknowledged.
Informational success codes to know
Two codes in the success range that commonly confuse developers:
0x10No matching subscribers: the PUBLISH was accepted and processed; it just had no current subscribers whose topic filters matched. The message was not lost — it may be retained or queued depending on QoS. Do not alert on this code.0x11No subscription existed: the client requested to UNSUBSCRIBE from a topic it was not subscribed to. The broker processed the UNSUBSCRIBE cleanly; there is nothing to fix.
Common error codes and what to do
| Code | Name | Likely cause | Fix |
|---|---|---|---|
0x87 | Not authorized | ACL mismatch, wrong credentials | Check broker ACL rules and credentials |
0x8D | Keep Alive timeout | Client not sending PINGREQ on schedule | Increase keep-alive or fix network |
0x8E | Session taken over | Another client connected with same ID | Ensure unique client IDs |
0x95 | Packet too large | Message exceeds broker’s max packet size | Reduce payload, check broker config |
0x97 | Quota exceeded | Rate or message quota hit | Throttle client, adjust broker limits |
A clean session trace
CONNECT → CONNACK 0x00 Success
SUBSCRIBE → SUBACK 0x01 Granted QoS 1
PUBLISH (QoS1) → PUBACK 0x00 Success
DISCONNECT → (broker sends 0x00 Normal disconnection on clean close)
Any deviation from 0x00 in this sequence is diagnostic signal. Search this reference by hex value, decimal value, name, or packet type to find what a code means in your context.