The single most important idea in MQTT is that clients do not talk to each other directly. They talk through an intermediary, and they do so using a messaging pattern called publish/subscribe, almost always shortened to pub/sub. Every other feature of the protocol, from Quality of Service to retained messages to shared subscriptions, is built on top of this pattern. If you understand pub/sub, the rest of MQTT follows naturally.
This article explains what the publish/subscribe pattern is, how it differs from the traditional client-server model, the three forms of decoupling it provides, the central role the broker plays, how message filtering works, why the pattern scales, and how it differs from a true message queue. It is a technical reference; related mechanisms such as topics, Quality of Service, and sessions each have their own dedicated articles in this category.
Table of Contents
Pub/sub at a glance
| Aspect | Publish/subscribe (MQTT) | Traditional client-server |
|---|---|---|
| Communication | Indirect, through a broker | Direct, client to endpoint |
| Sender knows receiver? | No | Yes |
| Receiver knows sender? | No | Yes |
| Relationship | One-to-many, many-to-many | One-to-one |
| Must both be online? | No (with sessions/QoS) | Usually yes |
| Filtering done by | The broker | The endpoint or client |
| Coupling | Decoupled in space, time, sync | Tightly coupled |
The problem with direct communication
In a traditional client-server architecture, a client communicates directly with a known endpoint. A web browser opens a connection to a specific web server. A database client connects to a specific database host. The sender must know the receiver’s address, both must be available at the same time, and the sender typically blocks while waiting for a response.
That model works well for many things, but it scales poorly for the kind of system MQTT targets: large numbers of devices, many of them constrained, on unreliable networks, where any participant might be offline at any moment and where the same piece of information often needs to reach several consumers at once.
Consider a temperature sensor whose reading is needed by a logging database, a dashboard, and an alerting service. In a direct model, the sensor would need to know the address of all three, open connections to all three, and handle the case where any of them is down. Add a fourth consumer later and you have to modify and redeploy the sensor’s firmware. Multiply that across thousands of devices and the design collapses under its own coupling.
Publish/subscribe removes this coupling entirely.
How publish/subscribe works
In the pub/sub model, the component that sends a message is the publisher, and the components that receive messages are subscribers. The crucial point is that they never communicate directly and, in general, are completely unaware of each other. Neither the publisher nor the subscriber knows the other exists.
Sitting between them is a third component, the broker. Every message flows through the broker. A publisher sends a message to the broker, tagged with a topic. Subscribers tell the broker which topics they are interested in. The broker’s job is to take each incoming message and route it to exactly the clients that asked for that topic.
Returning to the temperature sensor: the sensor publishes its reading to a topic such as home/livingroom/temperature and sends it to the broker. It does not know or care who is listening. The logging database, the dashboard, and the alerting service have each separately subscribed to that topic with the broker. When the message arrives, the broker delivers a copy to all three. To add a fourth consumer, you simply have it subscribe; the sensor is never touched.
The three dimensions of decoupling
The separation that pub/sub creates is called decoupling, and it is useful to break it into three independent dimensions, because each one solves a different real-world problem.
Space decoupling
The publisher and subscriber do not need to know each other’s network identity. Neither needs the other’s IP address or port. Each only needs to be able to reach the broker. This is what lets you add, remove, or relocate consumers without ever reconfiguring the producers, and vice versa. A sensor in the field has no embedded list of who consumes its data; it only knows the broker.
Space decoupling is also what makes MQTT work cleanly across NAT and firewalls. Because clients only ever initiate outbound connections to the broker, devices behind a router with private addresses participate with no special configuration.
Time decoupling
The publisher and subscriber do not need to be online at the same time. This is one of the most powerful properties for unreliable networks. Although most MQTT traffic is delivered in near real time, the broker can store messages for a subscriber that is currently offline and deliver them when it reconnects.
This is not unconditional. Two things must be true for the broker to hold messages for an offline client: the client must have connected with a persistent session, and it must have subscribed to the topic at a Quality of Service level greater than 0. Under those conditions, a device that loses its connection for minutes or hours can reconnect and receive everything it missed. The persistent sessions article covers exactly what the broker stores and how this works.
Synchronization decoupling
Operations on the publisher and subscriber are not interrupted while publishing or receiving. Most MQTT client libraries are asynchronous, built on callbacks or a similar event-driven model, so a client is not blocked while it waits for a message to arrive or for a publish to complete. The application can keep doing other work.
This matters for constrained devices that cannot afford to sit blocked on a network operation, and it matters for high-throughput consumers that need to process a continuous stream of incoming messages without stalling. Synchronous behavior is still possible where it is genuinely needed; some libraries expose synchronous APIs for waiting on a specific message. But the default and natural flow of MQTT is asynchronous.
The broker: the heart of pub/sub
Because publishers and subscribers never meet, the broker carries the entire weight of the system. It is the central hub through which every message must pass, and understanding its responsibilities is essential to understanding pub/sub.
The broker is responsible for:
- Receiving every published message from every connected publisher.
- Filtering messages to determine which subscribers are interested in each one.
- Delivering each message to the right subscribers, at the Quality of Service level each subscriber requested.
- Maintaining session state for persistent clients, including their subscriptions and any messages they missed while offline.
- Authenticating and authorizing clients, deciding who may connect and which topics each may publish or subscribe to.
A single broker, depending on its implementation, may handle anywhere from a handful of clients to many hundreds of thousands concurrently. Because it usually sits at the boundary between the field and backend systems, and is frequently exposed to the internet, a production broker needs to be highly scalable, easy to monitor, resilient to failure, and integratable with downstream infrastructure such as databases, stream processors, and enterprise service buses. Most brokers are extensible so operators can add custom authentication, authorization, and integration logic.
The broker’s centrality is also its main design consideration: it is a single point through which all traffic flows, so in large deployments it is run as a cluster of nodes behind load balancers rather than a single server. More on that under scalability below.
A message’s journey through the broker, step by step
It helps to trace a single message end to end to see how the pieces fit. Suppose a thermostat publishes a new reading and three consumers are interested.
- The thermostat connects. It opens a TCP connection to the broker and sends a CONNECT packet. The broker authenticates it, authorizes it, and replies with a CONNACK. The thermostat is now a connected client. It has no knowledge of any consumer.
- The consumers subscribe, independently and at different times. A logging service connects and sends a SUBSCRIBE for
home/livingroom/temperatureat QoS 1. A dashboard connects later and subscribes tohome/+/temperatureat QoS 0, using a single-level wildcard to catch every room. An alerting service connects and subscribes tohome/#at QoS 1, catching everything under the home hierarchy. The broker records all three subscriptions. None of the consumers knows the thermostat exists, and the thermostat does not know they exist. - The thermostat publishes. It sends a PUBLISH packet to the broker with topic
home/livingroom/temperature, payload21.5, and QoS 1. Its responsibility ends once the broker acknowledges receipt with a PUBACK. The thermostat never learns who, if anyone, will receive the reading. - The broker filters. It takes the published topic and matches it against every active subscription. The logging service’s exact subscription matches. The dashboard’s
home/+/temperaturematches because the wildcard covers thelivingroomlevel. The alerting service’shome/#matches because the multi-level wildcard covers everything beneathhome. Three matches. - The broker delivers, honoring each subscriber’s QoS. It sends a copy of the message to each matching subscriber. The logging service and alerting service subscribed at QoS 1, so the broker delivers at QoS 1 and waits for each PUBACK. The dashboard subscribed at QoS 0, so even though the publisher used QoS 1, the broker downgrades that delivery to QoS 0 for the dashboard, fire and forget. Each subscriber receives its own independent copy.
- A fourth consumer arrives later. A data-archival service is added to the system and subscribes to
home/livingroom/temperature. The thermostat’s firmware is never modified, redeployed, or even aware of the change. From the next publish onward, the archival service receives readings too.
This walkthrough shows every property discussed above in action: space decoupling (nobody knows anyone’s address), the broker’s filtering role, per-subscriber QoS and the downgrade behavior, the one-to-many fan-out of a single message, and the ability to extend the system without touching the producer. It also shows why topic design matters: the wildcard subscriptions only worked because the topic hierarchy was structured sensibly.
Message filtering: how the broker decides who gets what
The broker’s filtering is what makes pub/sub useful rather than a simple broadcast. There are several conceptual approaches to filtering, and it is worth knowing all three to understand why MQTT chose the one it did.
Subject-based filtering
This is the approach MQTT uses. Filtering is based on the subject, or topic, that is part of every message. A subscribing client tells the broker the topics it cares about, and from then on the broker ensures that client receives every message published to those topics. Topics are hierarchical strings, structured with forward slashes, which allows flexible filtering: a subscriber can match an exact topic or use wildcards to match whole families of topics at once.
Subject-based filtering is simple, fast, and does not require the broker to inspect message contents, which means payloads can be binary, encrypted, or any format at all. The cost is that publisher and subscriber must agree on the topic structure in advance, which is why topic design deserves careful planning. The topics article covers structure, wildcards, and conventions in detail.
Content-based filtering
In content-based filtering, the broker filters messages by inspecting the message body using a filter-query language. Subscribers register queries describing the messages they want. This is more flexible in theory, but it has a significant drawback: the content must be known and readable in advance, which means the payload cannot be encrypted and cannot be changed freely without breaking the filters. MQTT does not use content-based filtering as its base mechanism, though some brokers offer it as an extension layered on top.
Type-based filtering
When object-oriented languages are involved, filtering by the type or class of a message is common. A subscriber might listen for all messages of a particular type or any of its subtypes. This is a programming-language-level concept rather than a wire-protocol one, and is not how MQTT routes messages.
MQTT settled on subject-based filtering because it is the best fit for the protocol’s goals: it is lightweight, it keeps the broker’s work cheap, and it preserves the data-agnostic nature of the payload.
Why pub/sub scales
Publish/subscribe scales considerably better than the traditional client-server approach, for a few related reasons.
First, the broker’s work can be highly parallelized. Because each message is an independent event routed according to its topic, the broker can process many messages concurrently rather than serializing them through a request/response cycle with each client.
Second, messages are processed in an event-driven way. The broker reacts to incoming publishes and subscriptions as events, which suits high-volume streams of small messages, exactly the traffic profile MQTT was designed for.
Third, message caching and intelligent routing improve throughput. Brokers can cache routing information and optimize how messages move between internal nodes, reducing redundant work.
That said, scaling to millions of simultaneous connections is a genuine engineering challenge, not something the pattern gives you for free. The solution is to run the broker as a cluster of nodes that distribute the connection load across multiple servers, fronted by load balancers. The pub/sub pattern makes this possible because the decoupling means no client is tied to a specific server; any node in the cluster can accept any client, and the cluster coordinates routing internally. This is why production MQTT deployments at scale are built on clustered brokers rather than a single instance.
Things to consider before using pub/sub
The decoupling that makes pub/sub powerful also introduces a few characteristics that surprise developers coming from request/response systems. Being aware of them up front avoids confusion later.
Both sides must agree on the data structure
Because filtering is subject-based, both publisher and subscriber need to know which topics to use, and they need a shared understanding of how data is structured within those topics. This agreement is established by design, not discovered at runtime. Plan your topic tree carefully, and document the payload format for each topic, before you start publishing.
The publisher gets no delivery feedback about subscribers
When a client publishes a message, its only concern, and its only guarantee, is delivering that message safely to the broker. Once the broker has it, delivering it to subscribers is entirely the broker’s responsibility. The publishing client receives no feedback about whether anyone was interested in the message or how many subscribers received it.
This is a deliberate consequence of decoupling, but it means you cannot assume someone is listening. It is entirely possible to publish to a topic that has no subscribers, in which case the message simply goes nowhere. If your application needs to know that a specific recipient received and acted on a message, you must build that on top of the protocol. MQTT 5’s request/response pattern exists precisely for this purpose and is covered in its own article.
A message with no subscribers is not stored by default
Related to the above: if nobody is subscribed to a topic when a message is published, that message is not delivered to anyone and is not held for some future subscriber, unless it was published as a retained message. Retained messages are the mechanism for giving a newly connected subscriber the last known value on a topic, and they are covered in the retained messages article. This default behavior is one of the key differences between MQTT and a true message queue.
MQTT versus a traditional message queue
The name MQTT, with its historical “MQ,” leads many people to assume it is a message-queue protocol. It is not, and the distinction is important because the two behave differently in ways that affect how you design systems.
A traditional message queue and MQTT pub/sub differ in three fundamental ways:
Unconsumed messages. In a message queue, each incoming message is stored in the queue until a client, often called a consumer, picks it up. If no consumer takes it, the message remains in the queue and waits. A message cannot simply go unprocessed. In MQTT, by contrast, if no client is subscribed to a topic when a message is published, that message is delivered to no one.
One consumer versus all subscribers. In a traditional message queue, a given message is processed by exactly one consumer, and the load is distributed across the consumers attached to the queue. This is a work-distribution model. In MQTT, the behavior is the opposite: every subscriber to a topic receives its own copy of the message. This is a broadcast-to-interested-parties model.
Explicit creation versus on-the-fly topics. Queues are named and must be created explicitly with a separate command before they can be used; only after a queue exists can you publish to or consume from it. A queue is a relatively rigid, declared resource. MQTT topics are far more flexible: they are created on the fly simply by publishing or subscribing, with no prior initialization. The broker accepts any valid topic.
It is worth noting that MQTT can queue messages in certain cases, specifically for offline clients with persistent sessions and QoS 1 or 2 subscriptions. But that is a session feature, not evidence that MQTT is a message queue. The default and defining behavior is pub/sub, not queuing. If your use case genuinely needs work distribution, where each message should be handled by exactly one of several worker instances, MQTT 5 offers shared subscriptions to provide queue-like load balancing on top of the pub/sub model, covered in its own article.
Where the publish/subscribe pattern fits best
The characteristics described above make pub/sub a strong fit for particular classes of system, and a weaker fit for others. Knowing which is which helps you decide when MQTT is the right tool.
Pub/sub excels when one piece of information needs to reach several consumers. Telemetry is the classic case: a sensor reading that must simultaneously feed a live dashboard, a historian database, and an alerting rule. In a direct model, the producer would shoulder the burden of knowing and reaching every consumer. In pub/sub, it publishes once and the broker fans the message out, with new consumers added at any time without disturbing the producer.
It also excels when participants are intermittently connected. Mobile and remote devices drop offline routinely, and the time-decoupling property means a producer can keep publishing while a consumer is away, with the broker holding messages for delivery on reconnect. A system built on direct connections would have to handle every consumer’s availability explicitly, in the producer.
The pattern is a natural fit for event-driven and streaming architectures, where a continuous flow of small, independent messages is routed to whichever components care about each event. Because the broker processes messages as parallelizable events rather than serialized request/response cycles, throughput scales well, and clustering lets the system grow to very large numbers of connections.
Finally, pub/sub suits systems that must evolve over time. Because producers and consumers are decoupled, you can add, remove, replace, or relocate either side without coordinating changes on the other. A system assembled from components built by different teams, on different schedules, can integrate through shared topics without those teams needing tight coordination on addresses or availability.
Where pub/sub is a weaker fit is the synchronous, one-to-one request/response interaction: “send this exact query and block until I get exactly this answer back.” That is the domain HTTP was built for. MQTT can be made to do it, and MQTT 5’s request/response pattern standardizes the approach, but if every interaction in your system is a synchronous one-to-one call with no fan-out and no intermittent connectivity, the decoupling of pub/sub buys you little.
How this maps to the rest of MQTT
Almost every other MQTT concept is an elaboration of the publish/subscribe foundation laid out here:
- Topics and wildcards define the subjects that subject-based filtering operates on.
- Quality of Service governs the delivery guarantee for each of the two hops in a pub/sub exchange: publisher-to-broker and broker-to-subscriber.
- Persistent sessions are what make time decoupling possible, letting the broker hold messages for offline subscribers.
- Retained messages address the “no subscribers yet” gap by giving new subscribers the last known value.
- Last Will and Testament lets the broker publish on a client’s behalf when that client drops, which is itself a pub/sub action.
- Shared subscriptions (MQTT 5) overlay work distribution onto the broadcast model when you need queue-like behavior.
Understanding pub/sub as the base layer is what makes all of these features feel coherent rather than like a list of unrelated capabilities.
Frequently asked questions
What is the publish/subscribe pattern in MQTT?
It is a messaging model where senders (publishers) and receivers (subscribers) never communicate directly. Instead, publishers send messages tagged with a topic to a central broker, subscribers register their topics of interest with the broker, and the broker routes each message to all interested subscribers.
What is the role of the broker in pub/sub?
The broker is the intermediary that all messages pass through. It receives every published message, filters them by topic to determine who is interested, delivers each message to the right subscribers at the appropriate Quality of Service, maintains session state, and handles authentication and authorization.
Is MQTT publish/subscribe the same as a message queue?
No. In a message queue, each message is consumed by exactly one consumer and waits in the queue until consumed. In MQTT pub/sub, every subscriber to a topic gets its own copy, and a message with no subscribers is simply not delivered. Topics are also created on the fly, whereas queues must be created explicitly.
Can a publisher know if anyone received its message?
Not by default. The publisher’s only guarantee is delivery to the broker. It receives no information about how many subscribers, if any, received the message. To get end-to-end confirmation, you use MQTT 5’s request/response pattern.
Can publisher and subscriber be offline at different times?
Yes. This is called time decoupling. If a subscriber uses a persistent session and subscribes at QoS 1 or 2, the broker stores matching messages while it is offline and delivers them when it reconnects.
Why does pub/sub scale better than client-server?
Because the broker can process messages as independent, parallelizable events rather than serialized request/response cycles, and because decoupling lets the broker run as a cluster of nodes behind load balancers, distributing connections and message load across many servers.
