What Is MQTT? Protocol Architecture, Packets & How It Works

By | May 22, 2026

MQTT is a lightweight, publish/subscribe network protocol that transports messages between devices. It was built to move small amounts of data across networks where bandwidth is limited, latency is variable, and connections drop without warning. Those constraints, first encountered on remote industrial sites, are exactly the conditions found across the modern Internet of Things, which is why MQTT has become one of the most widely deployed messaging protocols in the world.

This guide explains what MQTT is, how the protocol actually works on the wire, the roles its components play, and the mechanisms (Quality of Service, sessions, retained messages, keep alive) that make it reliable over unreliable links. It is written as a technical reference. Each major mechanism summarized here has its own dedicated article in this category for readers who need to go deeper.

MQTT at a glance

PropertyDetail
Full nameHistorically “MQ Telemetry Transport”; now treated as a name, not an acronym
PatternPublish/subscribe (decoupled, broker-mediated)
TransportTCP/IP (TLS for security); WebSockets for browsers
Default ports1883 (plain), 8883 (TLS)
Current versionMQTT 5.0, an OASIS Standard ratified 7 March 2019; also an ISO/IEC standard
Previous versionMQTT 3.1.1 (OASIS Standard, 29 October 2014), still very widely deployed
Invented1999, by Andy Stanford-Clark (IBM) and Arlen Nipper (Arcom / Cirrus Link)
Header overheadFixed header as small as 2 bytes
Message types15 control packet types
Data modelData-agnostic binary payloads up to 256 MB

Why MQTT exists

To understand the design, it helps to understand the problem it was built for. In 1999, Andy Stanford-Clark of IBM and Arlen Nipper, then at Arcom, needed a way to connect oil pipeline sensors over satellite links. Those links were expensive per byte, intermittent, and the field devices ran on limited power. A protocol like HTTP, with its verbose text headers and request/response round trips, was a poor fit. They needed something that sent almost nothing extra over the wire and tolerated a connection that came and went.

They wrote down five requirements for the new protocol, and these still describe MQTT today:

  • Simple to implement. A client should be cheap to build, even on a tiny microcontroller.
  • Quality of Service for data delivery. The protocol itself should offer delivery guarantees, rather than pushing that burden onto every application.
  • Lightweight and bandwidth efficient. Minimal overhead per message.
  • Data agnostic. The protocol should not care what the payload contains.
  • Continuous session awareness. Both sides should be able to tell whether the other is still there.

Every one of those goals maps directly to a feature you will see below. The minimal fixed header satisfies bandwidth efficiency. Three Quality of Service levels satisfy delivery guarantees. The publish/subscribe model and binary payloads satisfy the data-agnostic and decoupling goals. The keep alive mechanism satisfies session awareness.

The name and the message-queue confusion

MQTT is no longer expanded as an acronym in the current specification; it is simply the protocol’s name. Historically it stood for “MQ Telemetry Transport,” where “MQ” referred to IBM’s MQ Series product line that the inventors named the protocol after.

This history causes a persistent misconception: that MQTT is a message-queue protocol. It is not a traditional message queue, and the distinction matters because it changes how you design with it:

  • In a true message queue, each message waits in the queue until exactly one consumer picks it up, and the load is distributed across consumers. In MQTT, every subscriber to a topic receives its own copy of each matching message.
  • In a message queue, a message cannot simply go unconsumed; it sits and waits. In MQTT, if no client is subscribed to a topic when a message is published, that message is delivered to no one (unless it is a retained message, covered later).
  • Queues must be created and named explicitly before use. MQTT topics are created on the fly, with no setup.

MQTT can queue messages for offline clients under specific conditions, but that is a feature of persistent sessions, not evidence that it is a queue.

From IBM to open standard

IBM used the protocol internally for roughly a decade, then released MQTT 3.1 as a royalty-free version in 2010, opening it for anyone to implement. Maintenance later moved to OASIS, a vendor-neutral standards body. MQTT 3.1.1 became an approved OASIS Standard on 29 October 2014 and was subsequently adopted as an ISO/IEC standard.

In March 2019, OASIS ratified MQTT 5.0, a substantial upgrade aimed at large-scale and cloud deployments, better error reporting, and protocol extensibility. MQTT 5.0 is the current standard, edited by representatives from IBM and Microsoft among others. MQTT 3.1.1 nevertheless remains extremely common in the field, and most brokers support both side by side, so understanding both versions is worthwhile.

The publish/subscribe model

The single most important concept in MQTT is that it does not use direct client-to-server communication. It uses publish/subscribe, usually shortened to pub/sub.

In a traditional client-server exchange, a client talks directly to a known endpoint. In pub/sub, the component that sends a message (the publisher) is separated from the component or components that receive it (the subscribers). They never communicate directly and generally have no knowledge of each other’s existence. A third component, the broker, sits between them. Every message flows through the broker, which filters incoming messages and routes each one to the clients that want it.

This separation is called decoupling, and it operates along three independent dimensions:

  • Space decoupling. Publisher and subscriber do not need each other’s network address. Neither needs the other’s IP or port. They each only need to reach the broker.
  • Time decoupling. They do not need to be online simultaneously. Under the right session and QoS conditions, the broker can hold messages for a subscriber that is currently offline and deliver them on reconnect.
  • Synchronization decoupling. Neither side has to block. Most client libraries are asynchronous and callback-driven, so publishing or receiving does not stop other work.

Why pub/sub scales

Decoupling is what lets MQTT scale far beyond direct client-server designs. Because the broker mediates everything, its work can be heavily parallelized and processed as a stream of events. Message caching and intelligent routing improve throughput further. Reaching millions of concurrent connections is still a genuine engineering challenge, but it is solved by clustering broker nodes and distributing load across servers behind load balancers, rather than by changing the protocol.

How filtering works

Routing the right message to the right subscriber is the broker’s core responsibility. There are several theoretical ways to filter messages, but MQTT uses one in particular:

  • Subject-based filtering, which MQTT uses, filters on the topic string attached to every message. Clients subscribe to the topics they care about, and the broker matches published topics against those subscriptions.
  • Content-based filtering filters on the message body using a query language. Its drawback is that the content must be known in advance and cannot be encrypted or freely changed, so MQTT does not use it as the base mechanism.
  • Type-based filtering filters by the class or type of a message and is mainly relevant in object-oriented contexts.

Because MQTT uses subject-based filtering, the topic is central to everything, which is why topic design (covered below and in its own article) deserves careful planning.

A design consequence to remember

The same decoupling that makes pub/sub powerful introduces a behavior that surprises newcomers: a publisher receives no information about who, if anyone, received its message. It is entirely possible to publish to a topic with zero subscribers, in which case the message simply goes nowhere. If your application needs confirmation that a specific recipient acted on a message, you build that on top, for example with MQTT 5’s request/response pattern. The protocol guarantees delivery to the broker, and from the broker to subscribers according to QoS; it does not guarantee that a subscriber exists.

The two roles: client and broker

Every MQTT deployment is built from two kinds of participant.

The client

An MQTT client is any device that runs an MQTT library and connects to a broker over a network. The definition is deliberately broad. A client can be a battery-powered sensor on a constrained wireless link running a minimal library, a gateway, a backend server, or a desktop application used for testing. If it speaks MQTT over a TCP/IP stack, it is a client.

The labels “publisher” and “subscriber” describe what a client is doing at a given moment, not separate kinds of device. A single client commonly does both: a field device might publish its readings and subscribe to a command topic at the same time.

The client side of MQTT is intentionally simple, which is a major reason the protocol suits small devices. Mature client libraries exist for essentially every relevant language and platform, including Android, Arduino, C, C++, C#, Go, iOS, Java, JavaScript, Python, and .NET.

The broker

The broker is the counterpart to the client and the heart of the system. Depending on the implementation, a single broker can serve anywhere from a handful of clients to many hundreds of thousands or more concurrently. Its responsibilities are:

  • Receiving every published message.
  • Filtering messages and determining which clients are subscribed to each.
  • Delivering each message to its subscribers at the appropriate QoS.
  • Holding the sessions of persistent clients, including their subscriptions and any messages they missed while offline.
  • Authenticating and authorizing clients.

Because every message passes through it, and because the broker is frequently the component directly exposed to the internet and connected to downstream systems, a production broker needs to be scalable, monitorable, integratable with backend infrastructure, and resilient to failure. Most brokers are extensible so operators can plug in custom authentication, authorization, and integrations.

How an MQTT connection is established

MQTT runs over TCP/IP. Both client and broker need a TCP/IP stack. In OSI terms, MQTT occupies the application layers (5–7), TCP sits at layer 4, and IP at layer 3.

A connection is always between one client and the broker. Clients never connect directly to one another. The exchange begins when the client opens a TCP connection and sends a CONNECT packet. The broker replies with a CONNACK (connect acknowledgement) carrying a status code. Once that handshake completes, the broker keeps the connection open until the client disconnects or the link breaks.

If the CONNECT is malformed, or too much time elapses between opening the socket and sending it, the broker closes the connection. This protects the broker from clients that would otherwise tie up resources.

Working through NAT

A frequent concern is that field devices sit behind routers performing network address translation (NAT), with private addresses such as 192.168.x.x or 10.0.x.x. This is not a problem. The client initiates the connection outbound to the broker’s public address, and because the connection stays open afterward for bidirectional traffic, NAT does not interfere. The broker never needs to initiate a connection to the client.

What the CONNECT packet carries

A well-formed CONNECT carries several fields. The most important:

  • ClientId. A unique identifier for the client. The broker uses it to track the client and its session state, so it should be unique per broker. In MQTT 3.1.1 you may send an empty ClientId if you need no stored state, but then the clean session flag must be true or the broker rejects the connection.
  • Clean Session / Clean Start. Tells the broker whether to maintain a persistent session (covered below). MQTT 5 renames and refines this as Clean Start plus a session expiry interval.
  • Username and Password. Optional credentials for authentication and authorization. Critically, unless the connection is encrypted with TLS, the password travels in plain text, so credentials should always be paired with secure transport.
  • Will (Last Will and Testament). An optional message and topic the broker will publish on the client’s behalf if the client disconnects ungracefully.
  • Keep Alive. A time interval, in seconds, defining the longest the client and broker may go without exchanging a packet.

What the CONNACK reply carries

When the broker receives a CONNECT, it must respond with a CONNACK containing two key pieces of information:

  • Session present flag. Tells the client whether the broker already holds a persistent session for it. With a clean session, this is always false. With a persistent session, it is true if stored session data exists for that ClientId, helping the client decide whether it must re-subscribe.
  • Return code (reason code in MQTT 5). Indicates whether the connection succeeded. The MQTT 3.1.1 codes are:
Return codeMeaning
0Connection accepted
1Connection refused — unacceptable protocol version
2Connection refused — identifier rejected
3Connection refused — server unavailable
4Connection refused — bad username or password
5Connection refused — not authorized

MQTT 5 greatly expands this set of reason codes, which is part of its improved error reporting.

MQTT packet structure on the wire

MQTT is a binary protocol, and its efficiency comes from how compact its packets are. Every MQTT control packet has up to three parts, though only the first is always present:

  1. Fixed header — always present.
  2. Variable header — present in some packet types.
  3. Payload — present in some packet types.

The fixed header

The fixed header can be as small as two bytes, which is the heart of MQTT’s low overhead.

The first byte is split into two 4-bit fields:

  • Bits 7–4: the control packet type. A 4-bit value identifying which of the 15 packet types this is.
  • Bits 3–0: flags. Type-specific flags. For most packet types these are reserved and fixed. The PUBLISH packet is the main exception: bit 3 is the DUP (duplicate) flag, bits 2–1 are the QoS level, and bit 0 is the RETAIN flag. As a worked example, the byte 0b00110011 (0x33) decodes to a PUBLISH packet with DUP = 0, QoS = 1, and RETAIN = 1.

The bytes that follow encode the Remaining Length, a variable-length integer giving the number of bytes left in the packet (variable header plus payload), not counting the bytes used to encode the length itself. This uses a continuation-bit scheme: values up to 127 fit in one byte, larger values use additional bytes, up to four bytes total, which is what allows MQTT to support payloads up to 256 MB while keeping small packets tiny.

The variable header and packet identifier

Some packet types include a variable header between the fixed header and the payload. Its contents depend on the packet type. A common element is the Packet Identifier, a two-byte integer used to match a packet with its acknowledgement. It is required (and must be non-zero) in PUBLISH (when QoS > 0), PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, and UNSUBACK. Packet identifiers are unique only within a single client-broker interaction; once a flow completes, the identifier can be reused, which is why it never needs to exceed 65,535.

The 15 control packet types

MQTT defines 15 control packet types. The high nibble of the first byte encodes the type; the table below shows each type with its first-byte hex value:

PacketFirst byte (hex)DirectionPurpose
CONNECT0x10Client → BrokerRequest a connection
CONNACK0x20Broker → ClientAcknowledge a connection
PUBLISH0x30Both waysCarry an application message
PUBACK0x40Both waysAcknowledge a QoS 1 PUBLISH
PUBREC0x50Both waysQoS 2 — publish received
PUBREL0x60Both waysQoS 2 — publish release
PUBCOMP0x70Both waysQoS 2 — publish complete
SUBSCRIBE0x80Client → BrokerSubscribe to topics
SUBACK0x90Broker → ClientAcknowledge a subscription
UNSUBSCRIBE0xA0Client → BrokerUnsubscribe from topics
UNSUBACK0xB0Broker → ClientAcknowledge an unsubscribe
PINGREQ0xC0Client → BrokerKeep-alive ping request
PINGRESP0xD0Broker → ClientKeep-alive ping response
DISCONNECT0xE0Both (MQTT 5)Graceful disconnect notification
AUTH0xF0Both (MQTT 5)Enhanced authentication exchange

The AUTH packet is new in MQTT 5. In MQTT 3.1.1, DISCONNECT could only be sent by the client; MQTT 5 makes it bidirectional so the broker can tell a client why it is being disconnected.

Topics and message filtering

Topics are how MQTT decides who receives which message. A topic is a UTF-8 string made of one or more levels separated by forward slashes, the level separator. For example, myhome/groundfloor/livingroom/temperature has four levels.

Topics are lightweight. Unlike a message queue, you do not create a topic before using it; the broker accepts any valid topic with no initialization. Topics are case-sensitive (Home/Temp and home/temp differ), must contain at least one character, and a lone forward slash is technically valid.

When subscribing, a client can match an exact topic or use wildcards. Wildcards work only for subscriptions, never for publishing:

  • Single-level wildcard + replaces exactly one level. myhome/+/temperature matches myhome/kitchen/temperature and myhome/bedroom/temperature, but not myhome/kitchen/floor/temperature.
  • Multi-level wildcard # covers all remaining levels and must be the last character, preceded by a slash. myhome/# matches everything beneath myhome. Subscribing to # alone delivers every message on the broker, which is an anti-pattern in any high-throughput system.

Topics beginning with $ are reserved, typically for broker statistics under the $SYS/ convention, and are excluded from # subscriptions. Good topic hygiene (no leading slash, no spaces, short and ASCII-only names) is covered in the dedicated topics article and matters because topic length is included in every message.

Quality of Service (QoS) is an agreement between sender and receiver about the delivery guarantee for a given message. It is one of MQTT’s defining features and the main reason it works well over flaky networks. There are three levels:

  • QoS 0 — at most once. Best-effort, fire-and-forget. No acknowledgement, no retransmission. The guarantee is the same as the underlying TCP connection and nothing more.
  • QoS 1 — at least once. The sender stores the message and resends until it receives a PUBACK. The message is guaranteed to arrive, but may arrive more than once, so receivers must tolerate duplicates.
  • QoS 2 — exactly once. A four-part handshake (PUBLISH → PUBREC → PUBREL → PUBCOMP) guarantees the message is delivered exactly once. It is the safest and slowest level.

A crucial subtlety: QoS is negotiated separately for the publisher-to-broker hop and the broker-to-subscriber hop. The publisher sets the QoS when sending; the broker delivers to each subscriber at the QoS that subscriber requested. If a subscriber asked for a lower QoS than the publisher used, the broker downgrades to the lower level for that subscriber. Choosing the right level is a tradeoff between reliability and overhead, explored fully in the QoS article.

Sessions, retained messages, and last will

Several mechanisms work together to make MQTT robust when clients come and go.

Persistent sessions. A client can ask the broker to remember its state across disconnections. In a persistent session the broker stores the client’s subscriptions, undelivered QoS 1 and 2 messages, and in-flight message state, all keyed to the ClientId. This spares constrained devices from re-subscribing on every reconnect and lets the broker queue messages for them while offline. MQTT 5 refines this with a session expiry interval, so a dead client’s session is cleaned up automatically after a configurable timeout rather than lingering forever.

Retained messages. Normally a new subscriber learns nothing about a topic until the next message is published, which could be hours away. A retained message solves this: a publisher sets the retain flag, and the broker stores that message as the last known good value for the topic. Any client that later subscribes to a matching topic immediately receives it. Only one retained message is stored per topic, and publishing a zero-byte retained message clears it.

Last Will and Testament (LWT). Because clients on unreliable networks often vanish without a clean disconnect, each client can register a will message in its CONNECT. If the broker detects an ungraceful disconnect, it publishes the will message to the will topic on the client’s behalf, notifying other clients of the loss. Combined with retained messages, LWT is the standard pattern for tracking a device’s online/offline status.

Keep alive and detecting dead connections

TCP is supposed to report a broken connection, but on mobile and satellite links it frequently does not. A connection can become “half-open,” appearing alive while silently discarding everything written to it. MQTT’s keep alive mechanism detects this.

At connection time the client declares a keep alive interval in seconds, the maximum it will allow to pass without sending a packet. If it has nothing else to send, it must send a PINGREQ, and the broker replies with a PINGRESP. If the broker hears nothing, neither a message nor a PINGREQ, within 1.5 times the keep alive interval, it considers the client dead, closes the connection, and publishes the client’s will message if one was set. The maximum keep alive value is 18 hours, 12 minutes, 15 seconds, and a value of 0 disables the mechanism. When a stale half-open connection lingers and the same client reconnects, the broker performs a “client take-over,” closing the old connection so the new one can proceed.

Security

MQTT itself is a messaging protocol, not a security protocol, so security is layered on top:

  • Transport encryption. TLS (typically on port 8883) encrypts the entire connection, protecting credentials and payloads. Without it, usernames and passwords sent in the CONNECT packet travel in plain text.
  • Authentication. Username/password is the baseline. Brokers can also authenticate clients with TLS client certificates, removing the need for credentials. MQTT 5 adds the AUTH packet and “enhanced authentication,” enabling challenge-response mechanisms such as SCRAM and Kerberos via the SASL framework, as well as token-based methods like OAuth, including re-authentication without dropping the connection.
  • Authorization. Brokers control which clients may publish or subscribe to which topics, typically through access-control lists keyed to client identity.

Designing topic structures with authorization in mind, and always using TLS for anything beyond a trusted network, are the foundations of a secure MQTT deployment.

MQTT 3.1.1 versus MQTT 5.0

MQTT 5.0 is an evolution rather than a rewrite. Everything in MQTT 3.1.1 (pub/sub, topics, QoS, sessions, retained messages, LWT, keep alive) still applies. The major additions in version 5 include:

  • User properties — arbitrary key-value metadata on almost any packet, similar to HTTP headers.
  • Reason codes and reason strings — far richer error reporting on acknowledgements and disconnects.
  • Session and message expiry intervals — automatic cleanup of stale sessions and time-limited messages.
  • Shared subscriptions — load balancing a topic’s messages across multiple client instances.
  • Topic aliases — substituting long topic strings with a short integer to save bandwidth.
  • Payload format indicator and content type — describing a payload so receivers process it without unpacking it.
  • Request/response pattern — standardized response topics and correlation data for end-to-end acknowledgements.
  • Flow control — negotiating how many unacknowledged messages each side will accept.
  • Bidirectional DISCONNECT and the AUTH packet — better disconnect feedback and enhanced authentication.

Each of these has its own article in this category.

When MQTT is the right choice

MQTT is well suited to scenarios with constrained devices, unreliable or low-bandwidth networks, large numbers of connections, and a need to push updates rather than poll for them. Its low overhead, delivery guarantees, and decoupled architecture make it a strong fit for telemetry, sensor data, status reporting, and command-and-control across distributed systems. Where you need request/response semantics with rich payloads over reliable links, a protocol like HTTP may fit better, and MQTT 5’s request/response pattern exists precisely to bridge that gap when you want both.

Frequently asked questions

Is MQTT a message queue?

No. Despite the historical “MQ” in its name, MQTT is a publish/subscribe protocol, not a traditional message queue. Every subscriber gets its own copy of a matching message, topics are created on the fly, and a message with no subscribers is simply not delivered.

What port does MQTT use?

1883 for unencrypted MQTT and 8883 for MQTT over TLS. MQTT over WebSockets commonly uses 80 or 443.

What is the difference between MQTT 3.1.1 and 5.0?

MQTT 5.0 keeps all of 3.1.1’s behavior and adds features for large-scale and cloud systems: user properties, expanded reason codes, session and message expiry, shared subscriptions, topic aliases, request/response, flow control, and enhanced authentication.

Does MQTT guarantee message delivery?

It guarantees delivery according to the chosen QoS level, between each pair of hops (publisher-to-broker and broker-to-subscriber). It does not guarantee that a subscriber exists for a given topic.

What transport does MQTT run on?

TCP/IP by default, with TLS for encryption. It can also run over WebSockets, which is how browsers act as MQTT clients. A separate variant, MQTT-SN, targets non-TCP/IP sensor networks.

Author: Zakaria El Intissar

I'm an automation and industrial computing engineer with 12 years of experience in power system automation, SCADA communication protocols, and electrical protection. I build tools and write guides for Modbus, DNP3, IEC 101/103/104, and IEC 61850 on ScadaProtocols.com to help engineers decode, analyze, and troubleshoot real industrial communication systems.