MQTT Packet Types
MQTT 5.0 defines 15 control packet types. Each packet starts with a fixed header where bits 7–4 encode the packet type (1–15) and bits 3–0 encode packet-specific flags. Packet type 0 is reserved.
15
Packet Types
Remaining length: variable-length encoding, 1–4 bytes (MQTT 5.0 §2.1.4)
Source: OASIS MQTT 5.0 §2.1.2 Table 2-1
Connection
CONNECT is the first packet sent by a client after establishing a TCP connection. It carries the client ID, optional credentials (username/password), Will message, keep-alive interval, and session settings. The broker responds with CONNACK. A second CONNECT from the same connection is a protocol error and causes disconnection.
CONNACK is the broker's response to CONNECT. It carries a reason code (0x00 = success) and a Session Present flag indicating whether the broker has an existing session for this client. In MQTT 5.0, it also carries server capabilities: Maximum QoS, Retain Available, Maximum Packet Size, Assigned Client Identifier, and more.
DISCONNECT signals a graceful connection closure. In MQTT 3.1.1, only the client could send DISCONNECT with no reason code. MQTT 5.0 allows both client and broker to send DISCONNECT with a reason code and optional properties. A client DISCONNECT with reason 0x00 (Normal Disconnection) tells the broker not to send the Will message.
AUTH is an MQTT 5.0-only packet that enables enhanced authentication – multi-step challenge-response authentication (e.g., SCRAM, Kerberos, custom challenge). AUTH packets flow between client and broker after CONNECT but before CONNACK, enabling an arbitrary number of authentication exchanges before the session is established.
Publish Flow
PUBLISH carries an application message from publisher to broker, or from broker to subscriber. The fixed header flags encode DUP (retransmission flag), QoS (0, 1, or 2), and RETAIN. For QoS 1, the broker responds with PUBACK. For QoS 2, the broker responds with PUBREC starting a four-part handshake. QoS 0 has no acknowledgement.
PUBACK is the acknowledgement for a QoS 1 PUBLISH packet. The receiver sends PUBACK after it has accepted responsibility for the message. In MQTT 5.0, PUBACK carries a reason code – 0x00 = Success, 0x10 = No matching subscribers (message accepted but no one is subscribed), 0x80+ = failure codes.
PUBREC is the first broker response in the QoS 2 four-part handshake: PUBLISH → PUBREC → PUBREL → PUBCOMP. When the broker receives a QoS 2 PUBLISH it stores the packet identifier and responds with PUBREC. The publisher must then send PUBREL. PUBREC in MQTT 5.0 carries a reason code.
PUBREL is the publisher's release command in the QoS 2 handshake. Sent after receiving PUBREC. When the broker receives PUBREL, it delivers the message to subscribers and responds with PUBCOMP. PUBREL fixed header flags are 0010 – bit 1 must always be set to 1 per the MQTT 5.0 spec §3.6.1.
PUBCOMP is the final packet in the QoS 2 handshake. Sent by the broker to the publisher after PUBREL is received and the message has been delivered. Both sides release the packet identifier after PUBCOMP. The QoS 2 flow is complete.
Subscribe
SUBSCRIBE registers one or more topic filters with the broker. Each filter has a requested QoS and, in MQTT 5.0, options: No Local, Retain As Published, and Retain Handling. The broker responds with SUBACK containing one reason code per requested filter. A single SUBSCRIBE may contain up to 65535 topic filter entries.
SUBACK is the broker's response to SUBSCRIBE. It contains one reason code per topic filter in the SUBSCRIBE packet, in the same order. Reason code 0x00/0x01/0x02 indicates the maximum QoS granted. 0x80+ indicates failure. A client should not assume successful subscription until SUBACK confirms each filter.
UNSUBSCRIBE removes one or more topic filter subscriptions from the broker. The broker responds with UNSUBACK. Each topic filter must match the string used in the original SUBSCRIBE exactly – wildcards are not expanded for matching. Fixed header byte is 0xA2 (flags 0010 mandatory).
UNSUBACK is the broker's response to UNSUBSCRIBE. In MQTT 5.0, it contains one reason code per topic filter in the UNSUBSCRIBE packet. Reason code 0x00 = Success (subscription removed), 0x11 = No Subscription Existed (filter was not active), 0x80+ = failure codes.
Keep-Alive
PINGREQ is a keep-alive heartbeat sent by the client. The client must send PINGREQ within the Keep Alive interval defined in CONNECT (in seconds). If the broker receives no packets from the client within 1.5× the Keep Alive time, it closes the connection. PINGREQ has no payload and no variable header – it is exactly 2 bytes: 0xC0 0x00.
PINGRESP is the broker's response to PINGREQ. Like PINGREQ, it is exactly 2 bytes: 0xD0 0x00. No payload, no variable header. If a client sends PINGREQ and does not receive PINGRESP within a reasonable timeout, it should close and reopen the network connection.