The MQTT publish subscribe model is the reason a temperature sensor, a dashboard and a billing service can share data without ever knowing each other's address. In this article you will learn how pub/sub differs from request/response, what the three kinds of decoupling mean in practice, and you will prove each one yourself with two terminal windows connected to a free broker.
Request/Response vs. Publish/Subscribe
Most developers learn networking through HTTP. A client opens a connection to a known server, asks a question and waits for the answer. That pattern is simple, but it couples the two parties tightly: the client must know the server's address, the server must be up at that exact moment, and the client blocks (or polls) until something comes back.
Publish/subscribe breaks that coupling by inserting an intermediary. In MQTT that intermediary is the broker. Clients never talk to each other; they only talk to the broker:
- A publisher sends a message with a topic such as
plant1/line2/press/temperature. - A subscriber tells the broker which topics it cares about, optionally with wildcards like
plant1/+/press/#. - The broker matches every incoming message against all active subscriptions and forwards a copy to each match.
If you are new to the role of the server in the middle, our guide to what an MQTT broker does covers routing, sessions and retained state in more detail.
| Aspect | Request/Response (HTTP) | MQTT Publish/Subscribe |
|---|---|---|
| Who knows whom | Client knows server address | Clients only know the broker |
| Direction | Client pulls | Broker pushes on arrival |
| Fan-out to many readers | One request per reader | One publish, many deliveries |
| Connection | Often short-lived | One long-lived TCP connection |
| Offline receivers | Request fails | Persistent sessions can queue |
The Three Kinds of Decoupling in the MQTT Publish Subscribe Model
Pub/sub literature usually describes three dimensions of decoupling. They are worth separating because each one solves a different IoT problem.
Space decoupling
Publishers and subscribers do not know each other's IP address, hostname or even how many of them exist. A sensor publishes to site/tank3/level; whether zero, one or fifty applications receive it is invisible to the sensor. This is what lets you add a new analytics service next year without touching firmware on thousands of devices already in the field.
Time decoupling
Publisher and subscriber do not need to be online simultaneously. MQTT provides two mechanisms for this:
- Retained messages. The broker keeps the last retained message per topic and hands it to any new subscriber immediately. A dashboard that starts at 09:00 still sees the valve state that was published at 06:00.
- Persistent sessions. A subscriber that connects with a clean start flag of false (and, in MQTT 5, a session expiry interval) keeps its subscriptions while disconnected, and the broker queues QoS 1 and QoS 2 messages for it.
Time decoupling is not unlimited. Queues are bounded by the broker's session expiry and quotas, so treat it as a buffer for short outages, not as long-term storage.
Synchronization decoupling
Neither side blocks the other. A publisher hands its message to the client library and carries on; the library deals with acknowledgements in the background. Subscribers receive messages through callbacks rather than waiting in a loop. On a microcontroller this means the main loop keeps reading sensors while network I/O happens asynchronously.
Topics: The Contract Between Publishers and Subscribers
Because there is no direct link between parties, the topic string is the only contract they share. Good topic design therefore matters more in MQTT than URL design does in REST:
- Go from general to specific:
company/site/area/line/device/measurement. - Keep levels stable and meaningful so wildcards stay useful.
- Never put secrets or personally identifiable data in topic names.
- Do not start topics with
$; that prefix is reserved for broker topics like$SYS. - Separate commands from telemetry, for example
.../cmd/...versus.../telemetry/....
The + wildcard matches exactly one level and # matches any number of trailing levels. A historian might subscribe to acme/#, while a line supervisor only needs acme/izmir/assembly/line4/+/status.
Try It: Two Clients on broker.connectmq.com
Nothing makes the model click faster than watching it happen. Install the Mosquitto command-line clients (mosquitto_pub and mosquitto_sub), then open two terminals. Pick a random suffix so your topics do not collide with anyone else on the free public MQTT broker. Remember that the public area is readable by everyone, so publish nothing sensitive.
Step 1: Start a subscriber
# Terminal A: subscribe with a wildcard
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-demo-7f3a \
-t "connectmq/demo/7f3a/#" -v
Step 2: Publish from another client
# Terminal B: publish two readings
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
-t "connectmq/demo/7f3a/room1/temperature" -m "21.4"
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
-t "connectmq/demo/7f3a/room2/temperature" -m "19.8"
Terminal A prints both messages with their topics. The publisher never learned where the subscriber was: that is space decoupling.
Step 3: Prove time decoupling with a retained message
Stop the subscriber with Ctrl+C. Now publish a retained value while nobody is listening:
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
-t "connectmq/demo/7f3a/door/state" -m "open" -r
Start the subscriber again. It immediately receives connectmq/demo/7f3a/door/state open even though the message was sent while it was offline. To clean up, publish an empty retained payload with -r -n.
Step 4: Fan-out
Open a third terminal with another subscriber (use a different client ID such as sub2-demo-7f3a). Publish once and both subscribers receive the message. One publish, many deliveries, and the publisher's code did not change.
A Programmatic Subscriber in Python
The same model in code shows synchronization decoupling: the callback fires whenever data arrives while your program stays free to do other work.
import time
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/7f3a"
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code)
client.subscribe(f"{PREFIX}/#", qos=1)
def on_message(client, userdata, msg):
print(f"{msg.topic} -> {msg.payload.decode()} (retained={msg.retain})")
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="py-sub-7f3a")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, 1883, keepalive=60)
client.loop_start()
try:
while True:
# Your application keeps working; messages arrive in the background.
time.sleep(5)
client.publish(f"{PREFIX}/heartbeat", str(int(time.time())), qos=1)
except KeyboardInterrupt:
client.loop_stop()
client.disconnect()
Why Pub/Sub Suits IoT So Well
- Unreliable links. Devices on cellular or Wi-Fi drop off regularly. Persistent sessions and QoS 1/2 let them catch up without custom retry logic. The MQTT QoS levels guide explains the delivery guarantees in detail.
- Many consumers per data point. The same vibration reading can feed a dashboard, an alerting script and a historian. Each subscribes independently.
- Outbound-only connections. Devices open a connection to the broker; nothing needs to connect into the device. That is much friendlier to NAT and firewalls than running an HTTP server on every sensor.
- Small packets. The fixed header can be two bytes, which keeps radio time and data plans low.
Common Pitfalls and How to Avoid Them
No subscriber is not an error. If you publish to a topic with no subscribers, the broker accepts it and discards it (unless retained). Developers sometimes assume a lost message is a network problem when it is really a typo in the topic. Subscribe to # under your prefix while debugging.
Duplicate client IDs. Two clients with the same ID kick each other off in a loop. Every connection needs a unique ID.
Over-broad wildcards in production. A service subscribed to # receives everything, including traffic it cannot handle. Scope subscriptions to the levels you need.
Expecting replies. Pub/sub has no built-in reply. If you need request/response semantics, MQTT 5 adds a response topic and correlation data, covered in our overview of MQTT 5 features.
Ordering across topics. MQTT preserves order per topic for a given QoS from one publisher, but not across different topics. Put a timestamp or sequence number in payloads when ordering matters.
From Demo to Production
The public broker is perfect for experiments, but it is shared and readable by everyone. For real devices you want authentication, TLS on port 8883 and your own isolated namespace. A fully managed MQTT service such as ConnectMQ gives you exactly that: create a broker in the portal, copy the generated username, password and client ID, and point the same code at port 8883 with TLS. ConnectMQ supports MQTT 3.1.1 and 5.0, so retained messages, session expiry and shared subscriptions work the way this article describes. For a broader walk-through of the protocol, start with our complete MQTT tutorial, or read how MQTT works at the packet level.
Get Started with ConnectMQ
Ready to move your pub/sub prototype onto a private broker? Sign up at app.connectmq.com and create a free Serverless broker in a couple of minutes, no credit card required. ConnectMQ's in-browser MQTT client and live topic explorer let you watch publishes and subscriptions flow without installing anything.
Frequently Asked Questions
Is MQTT publish subscribe the same as a message queue?
Not exactly. In MQTT every matching subscriber gets its own copy of each message, while a classic queue delivers each message to one consumer. MQTT 5 shared subscriptions add queue-like load balancing when you need it.
Can a client publish and subscribe at the same time?
Yes. A single MQTT connection can publish to some topics and subscribe to others, which is how most devices receive commands while sending telemetry.
What happens to messages when no one is subscribed?
The broker drops them, unless the message is retained, in which case the last retained value per topic is stored for future subscribers.
Do publishers know how many subscribers received a message?
No. Acknowledgements in MQTT are between the client and the broker only, which is exactly what keeps publishers and subscribers decoupled.



