Stand with Ukraine flag

MQTT GUIDE

8 min read

MQTT Reason Codes

Quick answer

A reason code is a single-byte status value MQTT 5.0 attaches to control packets that report an outcome (CONNACK, PUBACK, SUBACK, DISCONNECT and more). Values below 0x80 mean success or a normal outcome; 0x80 and above signal a failure and say why. It replaces MQTT 3.1.1’s near-silent failures with actionable feedback.

In MQTT 3.1.1, when something went wrong the broker often just closed the connection and left you guessing. MQTT 5.0 fixes that with reason codes: a single byte on every acknowledgement that says whether an operation succeeded and, if not, why.

How reason codes work

Most MQTT 5.0 control packets that report an outcome — CONNACK, PUBACK, SUBACK, DISCONNECT, AUTH and more — carry a reason code. The value range is split in two: anything below 0x80 is a success or normal outcome, and anything 0x80 or above is a failure. The sender may also attach an optional reason string with human-readable detail for logs.

Allowed Client Broker PUBLISH sensors/temp PUBACK 0x00 Success ✓ < 0x80 Refused Client Broker PUBLISH admin/config PUBACK 0x87 Not authorized ✗ ≥ 0x80
MQTT 5.0 turns each acknowledgement into a clear yes / no — with a reason on failure

Common reason codes

CodeNameTypical meaning
0x00Success / NormalThe operation succeeded
0x80Unspecified errorSomething failed without a more specific code
0x87Not authorizedThe client isn’t permitted to do this
0x97Quota exceededA broker limit was hit

Reason codes by packet

Each acknowledgement or control packet defines its own subset of reason codes, and the same code keeps the same meaning wherever it appears. Codes below 0x80 are a success or normal outcome; 0x80 and above signal a failure. Expand a packet below to see every reason code the MQTT 5.0 specification defines for it.

CONNACKThe broker’s answer to CONNECT · 22 codes (+ 6 legacy)

Returned by the broker on the CONNACK that answers a client’s CONNECT.

CodeNameMeaning
0x00SuccessThe connection is accepted
0x80Unspecified errorRefused without a more specific reason
0x81Malformed PacketThe CONNECT could not be parsed
0x82Protocol ErrorThe CONNECT broke a protocol rule
0x83Implementation specific errorValid packet, but rejected by this broker
0x84Unsupported Protocol VersionThe broker doesn’t support the requested MQTT version
0x85Client Identifier not validThe client ID is well-formed but not accepted
0x86Bad User Name or PasswordCredentials were malformed or wrong
0x87Not authorizedThe client is not authorized to connect
0x88Server unavailableThe broker is not available
0x89Server busyThe broker is busy; try again later
0x8ABannedThe client has been banned by an administrator
0x8CBad authentication methodThe requested authentication method isn’t supported
0x90Topic Name invalidThe Will topic is well-formed but not accepted
0x95Packet too largeThe CONNECT exceeded the maximum packet size
0x97Quota exceededAn implementation or administrative quota was exceeded
0x99Payload format invalidThe Will payload doesn’t match its payload format indicator
0x9ARetain not supportedThe Will asks to be retained, but the broker doesn’t support retained messages
0x9BQoS not supportedThe Will QoS exceeds what the broker supports
0x9CUse another serverThe client should temporarily use another broker
0x9DServer movedThe client should permanently use another broker
0x9FConnection rate exceededThe connection-rate limit was exceeded

For contrast, MQTT 3.1.1 defined only a small fixed set of CONNACK return codes — with no reason string, and nothing comparable for other packets:

CodeMQTT 3.1.1 CONNACK meaning
0x00Connection accepted
0x01Unacceptable protocol version
0x02Identifier rejected
0x03Server unavailable
0x04Bad user name or password
0x05Not authorized
PUBACK and PUBRECAcknowledge a received publish · 9 codes

Both acknowledge a received PUBLISH — PUBACK for QoS 1, PUBREC as the first step for QoS 2 — and share the same reason codes.

CodeNameMeaning
0x00SuccessThe message is accepted
0x10No matching subscribersAccepted, but no subscription matched — it reached no one
0x80Unspecified errorRejected without a more specific reason
0x83Implementation specific errorRejected by this broker
0x87Not authorizedThe client isn’t authorized to publish to this topic
0x90Topic Name invalidThe topic is well-formed but not accepted
0x91Packet Identifier in useThe packet identifier is already in use (session-state mismatch)
0x97Quota exceededA publish quota was exceeded
0x99Payload format invalidThe payload doesn’t match its payload format indicator
PUBREL and PUBCOMPFinish the QoS 2 handshake · 2 codes

The second and final steps of the QoS 2 handshake. Only two codes apply.

CodeNameMeaning
0x00SuccessThe QoS 2 handshake continues normally
0x92Packet Identifier not foundNo such packet identifier is known (session-state mismatch)
SUBACKResult per subscribed topic filter · 12 codes

Answers a SUBSCRIBE with one code per requested topic filter — the granted QoS on success, or why it failed.

CodeNameMeaning
0x00Granted QoS 0Subscription accepted at maximum QoS 0
0x01Granted QoS 1Subscription accepted at maximum QoS 1
0x02Granted QoS 2Subscription accepted at maximum QoS 2
0x80Unspecified errorRejected without a more specific reason
0x83Implementation specific errorRejected by this broker
0x87Not authorizedThe client isn’t authorized to subscribe to this topic filter
0x8FTopic Filter invalidThe topic filter is malformed
0x91Packet Identifier in useThe packet identifier is already in use
0x97Quota exceededA subscription quota was exceeded
0x9EShared Subscriptions not supportedThe broker doesn’t support shared subscriptions
0xA1Subscription Identifiers not supportedThe broker doesn’t support subscription identifiers
0xA2Wildcard Subscriptions not supportedThe broker doesn’t support wildcard subscriptions
UNSUBACKResult per unsubscribed filter · 7 codes

Answers an UNSUBSCRIBE with one code per topic filter.

CodeNameMeaning
0x00SuccessThe subscription was removed
0x11No subscription existedNo matching subscription was found
0x80Unspecified errorRejected without a more specific reason
0x83Implementation specific errorRejected by this broker
0x87Not authorizedThe client isn’t authorized to unsubscribe
0x8FTopic Filter invalidThe topic filter is malformed
0x91Packet Identifier in useThe packet identifier is already in use
DISCONNECTWhy a connection is closing · 29 codes

In MQTT 5.0 either side can send a DISCONNECT with a reason code. The Sent by column shows who may use each code.

CodeNameSent byMeaning
0x00Normal disconnectionClient or ServerClose cleanly; do not publish the Will
0x04Disconnect with Will MessageClientDisconnect, but ask the broker to publish the Will
0x80Unspecified errorClient or ServerNo specific reason given
0x81Malformed PacketClient or ServerA packet could not be parsed
0x82Protocol ErrorClient or ServerA protocol rule was violated
0x83Implementation specific errorClient or ServerRejected by the sender’s implementation
0x87Not authorizedServerThe client is not authorized
0x89Server busyServerThe broker is busy
0x8BServer shutting downServerThe broker is shutting down
0x8DKeep Alive timeoutServerNo packet arrived within 1.5× the keep-alive
0x8ESession taken overServerAnother connection used the same client ID
0x8FTopic Filter invalidServerA subscription topic filter is malformed
0x90Topic Name invalidClient or ServerA topic name is malformed
0x93Receive Maximum exceededClient or ServerToo many unacknowledged PUBLISHes — see flow control
0x94Topic Alias invalidClient or ServerA topic alias exceeded the maximum
0x95Packet too largeClient or ServerA packet exceeded the maximum size
0x96Message rate too highClient or ServerThe message rate was too high
0x97Quota exceededClient or ServerA quota was exceeded
0x98Administrative actionClient or ServerClosed by an administrative action
0x99Payload format invalidClient or ServerA payload didn’t match its payload format indicator
0x9ARetain not supportedServerThe broker doesn’t support retained messages
0x9BQoS not supportedServerThe requested QoS isn’t supported
0x9CUse another serverServerTemporarily connect to another broker
0x9DServer movedServerPermanently connect to another broker
0x9EShared Subscriptions not supportedServerThe broker doesn’t support shared subscriptions
0x9FConnection rate exceededServerThe connection-rate limit was exceeded
0xA0Maximum connect timeServerThe maximum connection time was exceeded
0xA1Subscription Identifiers not supportedServerThe broker doesn’t support subscription identifiers
0xA2Wildcard Subscriptions not supportedServerThe broker doesn’t support wildcard subscriptions
AUTHEnhanced-authentication exchange · 3 codes

Drives MQTT 5.0 enhanced authentication (for example SCRAM), exchanged between client and broker.

CodeNameMeaning
0x00SuccessAuthentication completed successfully
0x18Continue authenticationMore data is needed to finish authenticating
0x19Re-authenticateThe client asks to re-authenticate on the live connection

Reason codes in TBMQ

TBMQ returns MQTT 5.0 reason codes across its acknowledgement packets — CONNACK, PUBACK, SUBACK, DISCONNECT and more — so a client learns exactly why a connect, publish, or subscribe was refused rather than just seeing the connection drop. See the MQTT protocol guide for supported 5.0 behavior.

Frequently asked questions

What is a reason code in MQTT?

A single-byte value in an MQTT 5.0 acknowledgement packet that reports the outcome of an operation. Codes below 0x80 are success or normal outcomes; codes 0x80 and above indicate a failure and identify what went wrong.

Which packets carry reason codes?

CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK, DISCONNECT and AUTH. SUBACK carries one reason code per topic filter in the request.

What is a reason string?

An optional human-readable text field the sender can add next to the reason code to give more detail, meant for logging and diagnostics rather than for programmatic decisions.

Do reason codes exist in MQTT 3.1.1?

Not in the same way. MQTT 3.1.1 has a few CONNACK return codes and per-subscription SUBACK results, but a failed publish or an unexpected disconnect gave almost no feedback — often the broker just closed the connection. MQTT 5.0 adds reason codes across the board.

What does reason code 0x87 mean?

0x87 is “Not authorized”. For example, a broker returns it on PUBACK or SUBACK when a client tries to publish or subscribe to a topic its permissions don’t allow.

Run it yourself

TBMQ is a free, open-source MQTT broker built to scale. Spin it up in minutes or try the live demo — no install required.