MQTT Protocol: A Practical Guide with Code Examples, Libraries, and Real-World Use Cases

MQTT (Message Queuing Telemetry Transport) is a lightweight publish-subscribe messaging protocol designed for resource-constrained devices and unreliable networks. Created in 1999 for monitoring oil pipelines, it has become the de facto standard for IoT communication.

This guide provides practical knowledge: how MQTT works, when to use it, code examples in multiple languages, and production-ready use cases.


What is MQTT?

MQTT is a client-server protocol where:

  • Publishers send messages to topics
  • Subscribers receive messages from topics
  • A broker manages routing and delivery

Unlike HTTP request-response, MQTT uses publish-subscribe patterns, decoupling senders from receivers.

Key Features:

Lightweight: Minimal packet overhead (2-byte fixed header)
Low bandwidth: Ideal for cellular/satellite networks
Quality of Service (QoS): Three levels of delivery guarantee
Persistent sessions: Clients can resume after disconnect
Last Will and Testament: Automatic notification when clients disconnect unexpectedly
Retained messages: New subscribers immediately get the last message


MQTT Architecture

┌─────────────┐         ┌─────────────┐         ┌─────────────┐
│  Publisher  │         │    Broker   │         │ Subscriber  │
│   (Client)  │────────▶│   (Server)  │────────▶│   (Client)  │
└─────────────┘         └─────────────┘         └─────────────┘
                              │
                              │ Topic: "home/temperature"
                              ▼
                        ┌─────────────┐
                        │  Subscriber │
                        │   (Client)  │
                        └─────────────┘

Components:

  1. MQTT Broker: Central server (Mosquitto, HiveMQ, EMQX, AWS IoT Core)
  2. MQTT Clients: Publishers and subscribers (sensors, gateways, applications)
  3. Topics: Hierarchical strings like home/bedroom/temperature
  4. Messages: Payload (binary or text) + metadata (QoS, retain flag)

Topics and Wildcards

Topics use / as a separator:

home/livingroom/temperature
home/livingroom/humidity
home/bedroom/temperature
factory/line1/robot/status
factory/line1/robot/error

Wildcard Subscriptions:

  • + (single-level): Matches one level
    home/+/temperature → matches home/livingroom/temperature, home/bedroom/temperature

  • # (multi-level): Matches all remaining levels
    factory/line1/# → matches factory/line1/robot/status, factory/line1/robot/error, factory/line1/sensor/data


Quality of Service (QoS) Levels

QoSNameDelivery GuaranteeUse Case
0At most onceFire and forget, no acknowledgmentNon-critical sensor data, high-frequency telemetry
1At least onceAcknowledged, possible duplicatesMost IoT applications, smart home
2Exactly onceGuaranteed once, no duplicatesBilling, critical commands, industrial control

Example Scenarios:

  • QoS 0: Room temperature updates every 10 seconds (losing one reading is acceptable)
  • QoS 1: Door lock status (important, but handling duplicates is easy)
  • QoS 2: Payment transactions or industrial valve control (must be exactly once)

Retained Messages and Last Will

Retained Messages:

When you publish with the retain flag, the broker stores the message. New subscribers immediately get it.

Use case: Device status

Topic: device/sensor123/status
Payload: "online"
Retain: true

New subscribers instantly know the device is online without waiting for the next update.

Last Will and Testament (LWT):

Set a message that the broker publishes if your client disconnects unexpectedly.

Use case: Offline detection

LWT Topic: device/sensor123/status
LWT Payload: "offline"

If the device crashes or loses network, the broker publishes "offline" automatically.


MQTT Brokers

BrokerTypeBest For
MosquittoOpen-sourceDevelopment, small deployments, Raspberry Pi
EMQXOpen-source, enterpriseHigh scalability, millions of connections
HiveMQCommercialEnterprise IoT, compliance, support
AWS IoT CoreCloudAWS ecosystem, serverless integration
Azure IoT HubCloudAzure ecosystem, device twins
Google Cloud IoT CoreCloud (deprecated)Legacy projects

Quick Mosquitto Setup (Ubuntu/Debian):

sudo apt update
sudo apt install mosquitto mosquitto-clients

# Start broker
sudo systemctl start mosquitto
sudo systemctl enable mosquitto

# Test with command-line tools
mosquitto_sub -h localhost -t "test/topic" &
mosquitto_pub -h localhost -t "test/topic" -m "Hello MQTT"

MQTT Libraries by Language

C / C++

1. Eclipse Paho MQTT C
Standard library for embedded Linux and microcontrollers.

#include "MQTTClient.h"

#define ADDRESS     "tcp://localhost:1883"
#define CLIENTID    "ExampleClient"
#define TOPIC       "home/temperature"
#define QOS         1

int main() {
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;

    MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    MQTTClient_connect(client, &conn_opts);

    pubmsg.payload = "22.5";
    pubmsg.payloadlen = 4;
    pubmsg.qos = QOS;
    pubmsg.retained = 0;

    MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
    MQTTClient_waitForCompletion(client, token, 10000);

    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    return 0;
}

Install: sudo apt install libpaho-mqtt-dev
Link: gcc mqtt_example.c -o mqtt_example -lpaho-mqtt3c


2. Mosquitto C Library

#include <mosquitto.h>

void on_connect(struct mosquitto *mosq, void *obj, int rc) {
    printf("Connected with code %d\n", rc);
    mosquitto_subscribe(mosq, NULL, "home/#", 0);
}

void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) {
    printf("Topic: %s, Payload: %s\n", msg->topic, (char *)msg->payload);
}

int main() {
    mosquitto_lib_init();
    struct mosquitto *mosq = mosquitto_new("subscriber", true, NULL);
    
    mosquitto_connect_callback_set(mosq, on_connect);
    mosquitto_message_callback_set(mosq, on_message);
    
    mosquitto_connect(mosq, "localhost", 1883, 60);
    mosquitto_loop_forever(mosq, -1, 1);
    
    mosquitto_destroy(mosq);
    mosquitto_lib_cleanup();
    return 0;
}

Install: sudo apt install libmosquitto-dev
Link: gcc mqtt_sub.c -o mqtt_sub -lmosquitto


Python

Paho MQTT Python

import paho.mqtt.client as mqtt
import time

# Callbacks
def on_connect(client, userdata, flags, rc):
    print(f"Connected with result code {rc}")
    client.subscribe("home/+/temperature")

def on_message(client, userdata, msg):
    print(f"Topic: {msg.topic}, Payload: {msg.payload.decode()}")

# Publisher
def publish_example():
    client = mqtt.Client()
    client.connect("localhost", 1883, 60)
    client.publish("home/livingroom/temperature", "23.5", qos=1, retain=True)
    client.disconnect()

# Subscriber
def subscribe_example():
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect("localhost", 1883, 60)
    client.loop_forever()

if __name__ == "__main__":
    # publish_example()
    subscribe_example()

Install: pip install paho-mqtt


JavaScript / Node.js

MQTT.js

const mqtt = require('mqtt');

// Publisher
const client = mqtt.connect('mqtt://localhost:1883');

client.on('connect', () => {
    console.log('Connected');
    
    // Publish
    client.publish('home/livingroom/temperature', '24.1', { qos: 1, retain: true });
    
    // Subscribe
    client.subscribe('home/+/temperature', (err) => {
        if (!err) console.log('Subscribed');
    });
});

client.on('message', (topic, message) => {
    console.log(`Topic: ${topic}, Message: ${message.toString()}`);
});

Install: npm install mqtt


Go

Paho MQTT Go

package main

import (
    "fmt"
    "time"
    mqtt "github.com/eclipse/paho.mqtt.golang"
)

func main() {
    opts := mqtt.NewClientOptions().AddBroker("tcp://localhost:1883")
    opts.SetClientID("go-client")
    
    client := mqtt.NewClient(opts)
    if token := client.Connect(); token.Wait() && token.Error() != nil {
        panic(token.Error())
    }
    
    // Subscribe
    client.Subscribe("home/+/temperature", 0, func(client mqtt.Client, msg mqtt.Message) {
        fmt.Printf("Topic: %s, Payload: %s\n", msg.Topic(), msg.Payload())
    })
    
    // Publish
    token := client.Publish("home/bedroom/temperature", 0, true, "21.3")
    token.Wait()
    
    time.Sleep(10 * time.Second)
    client.Disconnect(250)
}

Install: go get github.com/eclipse/paho.mqtt.golang


Rust

rumqtt

use rumqttc::{Client, MqttOptions, QoS};
use std::time::Duration;

fn main() {
    let mut mqttoptions = MqttOptions::new("rust-client", "localhost", 1883);
    mqttoptions.set_keep_alive(Duration::from_secs(5));

    let (mut client, mut connection) = Client::new(mqttoptions, 10);
    
    client.subscribe("home/+/temperature", QoS::AtMostOnce).unwrap();
    client.publish("home/office/temperature", QoS::AtLeastOnce, true, "22.0").unwrap();

    for notification in connection.iter() {
        println!("Notification = {:?}", notification);
    }
}

Install: Add to Cargo.toml: rumqttc = "0.23"


Real-World Use Cases

1. Smart Home Automation

Scenario: Control lights, thermostats, and sensors.

Architecture:

  • Home Assistant publishes to home/livingroom/light/set
  • ESP32 devices subscribe and toggle GPIO
  • Sensors publish to home/bedroom/temperature

Example:

# Turn on living room light
mosquitto_pub -t "home/livingroom/light/set" -m "ON"

# Subscribe to all temperature sensors
mosquitto_sub -t "home/+/temperature"

2. Industrial IoT Monitoring

Scenario: Monitor factory machines and send alerts.

Topics:

factory/line1/machine1/temperature
factory/line1/machine1/vibration
factory/line1/machine1/status
factory/line1/machine1/errors

QoS Strategy:

  • Temperature/vibration: QoS 0 (high frequency, non-critical)
  • Status changes: QoS 1 (important)
  • Emergency stop commands: QoS 2 (critical)

3. Fleet Tracking

Scenario: Track delivery vehicles with GPS.

MQTT Flow:

  1. Vehicle publishes GPS coordinates every 30 seconds to fleet/vehicle123/gps
  2. Backend subscribes to fleet/+/gps
  3. Dashboard updates in real-time
  4. LWT topic fleet/vehicle123/status set to “offline” for connectivity loss

Benefits over HTTP polling:

  • Lower bandwidth (persistent connection)
  • Real-time updates (no polling delay)
  • Automatic offline detection (LWT)

4. Agricultural Monitoring

Scenario: Monitor soil moisture, temperature, and irrigation.

Devices:

  • Soil sensors (ESP32, battery-powered)
  • Weather station (Raspberry Pi)
  • Irrigation controller (PLC)

Topics:

farm/field1/soil/moisture → QoS 0, retain=true
farm/field1/irrigation/valve → QoS 2, retain=true
farm/weather/temperature → QoS 0

Power Optimization:

  • ESP32 deep sleep, wake every 15 minutes
  • Publish with QoS 0 (saves battery)
  • Persistent session with clean_session=0

5. Home Energy Monitoring

Scenario: Monitor electricity usage and solar production.

Architecture:

  • Smart meter publishes to home/power/consumption
  • Solar inverter publishes to home/solar/production
  • Python script calculates net usage and stores in InfluxDB
  • Grafana dashboard visualizes data

Python Example:

import paho.mqtt.client as mqtt
from influxdb import InfluxDBClient

influx = InfluxDBClient(host='localhost', port=8086, database='energy')

def on_message(client, userdata, msg):
    value = float(msg.payload.decode())
    json_body = [{
        "measurement": msg.topic.replace("/", "_"),
        "fields": {"value": value}
    }]
    influx.write_points(json_body)

client = mqtt.Client()
client.on_message = on_message
client.connect("localhost", 1883)
client.subscribe("home/#")
client.loop_forever()

MQTT vs Other Protocols

ProtocolPatternOverheadUse Case
MQTTPub/SubVery lowIoT, real-time telemetry
HTTP/RESTRequest/ResponseHighWeb APIs, CRUD operations
WebSocketBidirectionalMediumWeb dashboards, chat
CoAPRequest/ResponseVery lowConstrained devices (UDP)
AMQPPub/Sub + QueueHighEnterprise messaging

When to choose MQTT:

  • Unreliable networks (cellular, satellite)
  • Battery-powered devices
  • Many-to-many communication
  • Real-time updates needed

When NOT to use MQTT:

  • Simple HTTP GET/POST is sufficient
  • No broker infrastructure available
  • Strict regulatory compliance for message routing

Security Best Practices

1. Use TLS/SSL (MQTTS)

client = mqtt.Client()
client.tls_set(ca_certs="/path/to/ca.crt")
client.connect("broker.example.com", 8883)  # Port 8883 for MQTTS

2. Username/Password Authentication

# Mosquitto: create password file
mosquitto_passwd -c /etc/mosquitto/passwd username

# Configure mosquitto.conf
allow_anonymous false
password_file /etc/mosquitto/passwd

3. Access Control Lists (ACL)

# /etc/mosquitto/acl
user sensor1
topic read home/livingroom/#

user controller
topic readwrite home/livingroom/light/set

4. Network Segmentation

  • IoT devices on separate VLAN
  • Broker not directly exposed to internet
  • Use VPN or reverse proxy for remote access

Common Pitfalls

❌ Using QoS 2 Everywhere

Problem: Highest latency and broker load
Solution: Use QoS 0 for telemetry, QoS 1 for most cases, QoS 2 only when critical

❌ Not Setting LWT

Problem: No way to detect unexpected disconnections
Solution: Always set Last Will and Testament for status topics

❌ Deep Topic Hierarchies

Problem: building/floor/wing/room/device/sensor/type/unit (hard to manage)
Solution: Keep 3-5 levels max: site/device/metric

❌ Large Payloads

Problem: Sending 1MB JSON in MQTT message
Solution: MQTT is for small messages; use HTTP/FTP for large files, send URL via MQTT


Debugging MQTT

Command-Line Tools:

# Subscribe to all topics (# wildcard)
mosquitto_sub -h localhost -t "#" -v

# Publish with retain
mosquitto_pub -h localhost -t "test/topic" -m "Hello" -r

# Publish with QoS 2
mosquitto_pub -h localhost -t "test/topic" -m "Critical" -q 2

# Subscribe with authentication
mosquitto_sub -h broker.example.com -p 8883 -u user -P pass -t "data/#" --cafile ca.crt

GUI Tools:

  • MQTT Explorer: Desktop app for browsing topics and debugging
  • HiveMQ Webclient: Browser-based client
  • MQTT.fx: Java-based MQTT client

Conclusion

MQTT is the ideal protocol for IoT and embedded systems when you need:

  • Lightweight, low-bandwidth communication
  • Publish-subscribe decoupling
  • Reliable delivery with QoS levels
  • Real-time data distribution

Start with Mosquitto broker for development, use Paho libraries for clients, and design your topic hierarchy before scaling. MQTT’s simplicity and efficiency make it the backbone of modern IoT infrastructure.


Further Reading


Are you using MQTT in production? What challenges have you faced? Share your experience in the comments.