MQTT is a lightweight messaging protocol that enables message publishing and subscribing in a publish-subscribe pattern over TCP.
Let’s see it in action with a simple setup. We’ll use mosquitto as our broker and two mosquitto_sub and mosquitto_pub clients.
First, start the broker:
mosquitto -v
This command starts the Mosquitto MQTT broker in verbose mode, listening for client connections on the default port 1883.
Now, in a separate terminal, subscribe to a topic:
mosquitto_sub -h localhost -t "my/test/topic"
This client connects to the broker on localhost and tells it, "I want to receive any messages sent to the topic my/test/topic."
In another terminal, publish a message:
mosquitto_pub -h localhost -t "my/test/topic" -m "Hello, MQTT!"
This client connects to the broker and publishes the message "Hello, MQTT!" to the topic my/test/topic.
Immediately, the mosquitto_sub client will receive and print:
Hello, MQTT!
The core problem MQTT solves is efficient, low-bandwidth communication between numerous devices, especially in unreliable networks. Traditional request-response models are too chatty and inefficient for IoT scenarios where devices might have limited power, processing, or network connectivity. MQTT’s publish-subscribe model decouples senders (publishers) from receivers (subscribers) through a central broker. Publishers don’t need to know who is listening, and subscribers don’t need to know who is sending. They only need to agree on a common topic.
Internally, MQTT operates over TCP. The broker manages client connections and message routing. When a client connects, it establishes a TCP connection with the broker. It then sends a CONNECT packet, which includes a client ID, optional username/password, and a "keep alive" interval. The broker responds with a CONNACK packet, indicating success or failure.
Publishing a message involves sending a PUBLISH packet. This packet contains the topic name, the message payload, and flags like Quality of Service (QoS) levels and whether the message should be retained. Subscribers express their interest by sending a SUBSCRIBE packet, specifying the topics they want to listen to and the desired QoS level for each. The broker then routes incoming PUBLISH packets to all connected subscribers whose subscriptions match the published topic.
The Quality of Service (QoS) levels are crucial for reliability:
- QoS 0 (At most once): The message is sent once, with no guarantee of delivery. It’s like a fire-and-forget message.
- QoS 1 (At least once): The sender ensures the message is received at least once. The receiver sends an acknowledgment (
PUBACK) upon receipt. If the sender doesn’t receive thePUBACKwithin a certain time, it resends the message. This guarantees delivery but might result in duplicate messages. - QoS 2 (Exactly once): The sender and receiver engage in a four-way handshake to ensure the message is delivered exactly once. This is the most reliable but also the most overhead.
The WILL message is a powerful feature for handling disconnections gracefully. A client can, during its initial CONNECT packet, specify a "last will and testament" message. This message, along with a topic and QoS, is stored by the broker. If the client disconnects abnormally (without sending a DISCONNECT packet), the broker will publish the will message on behalf of the client. This is invaluable for detecting device failures or network outages. For instance, a device could publish a "going offline" message to a status topic, and subscribers would know to treat it as unavailable if they receive that message.
The retained message feature allows a publisher to mark a message with the RETAIN flag set to 1. The broker will store the last retained message for each topic. When a new subscriber connects and subscribes to a topic, the broker will immediately send them the last retained message for that topic, if one exists. This is useful for providing clients with the most recent state upon connection, without requiring a historical message log.
The topic structure itself is hierarchical, using forward slashes (/) as separators, similar to file system paths. Clients can subscribe to specific topics (e.g., sensors/temperature/room1) or use wildcards. The single-level wildcard is + (e.g., sensors/+/room1 would match sensors/temperature/room1 and sensors/humidity/room1). The multi-level wildcard is # (e.g., sensors/# would match any topic under sensors/, including sensors/temperature/room1, sensors/humidity/room1, and even sensors/status).
The next concept you’ll likely grapple with is how to manage security and authentication in an MQTT deployment.