MQTT MESSAGING
The dominant pub/sub protocol for IoT. Broker architecture, QoS, topic design, TLS, retained messages, LWT, and production deployment for ESP32 and cloud platforms.
@mqtt
OVERVIEW
MQTT (Message Queuing Telemetry Transport) is a lightweight publish/subscribe messaging protocol designed for constrained devices on unreliable networks. It runs over TCP, uses a central broker, and provides three QoS levels from fire-and-forget to exactly-once delivery.
QOS LEVELS
| QoS | Guarantee | Packets | Use Case |
|---|---|---|---|
| 0 | At most once (fire & forget) | PUBLISH only | Sensor telemetry (high freq, loss OK) |
| 1 | At least once (may duplicate) | PUBLISH + PUBACK | Alerts, commands (idempotent handlers) |
| 2 | Exactly once | 4-packet handshake | OTA triggers, financial (expensive) |
Never use QoS 2 for high-frequency telemetry. The 4-packet handshake per message creates 4x overhead and bottlenecks the broker. Use QoS 0 for telemetry, QoS 1 for commands, QoS 2 only for critical one-shot events.
TOPIC ARCHITECTURE
Naming Convention
{org}/{site}/{zone}/{device_type}/{device_id}/{data_type}
2nth/hillcrest-dc/zone-a/temp-sensor/ts-001/telemetry
2nth/hillcrest-dc/zone-a/temp-sensor/ts-001/status
2nth/hillcrest-dc/zone-a/temp-sensor/ts-001/cmd
Wildcards
+single level:2nth/+/zone-a/+/+/telemetry#multi-level:2nth/hillcrest-dc/#- Subscribe-only — cannot publish to wildcard topics
Retained Messages & Last Will
Retained: Broker stores last message per topic. New subscribers get current state immediately. Essential for device status and config.
LWT (Last Will and Testament): Set at CONNECT time. Broker auto-publishes if client disconnects ungracefully — instant offline detection.
BROKER SELECTION
Open Source
| Broker | Language | Clustering | Best For |
|---|---|---|---|
| Mosquitto | C | Bridge only | Single-node, <100K conn, edge |
| EMQX | Erlang | Built-in | Production cloud, >100K conn |
| NanoMQ | C | No | Edge gateway, embedded |
| VerneMQ | Erlang | Yes | Mid-scale production |
Managed Cloud
| Service | Max Msg | Best For |
|---|---|---|
| AWS IoT Core | 128 KB | AWS-native, device shadows, fleet |
| Azure IoT Hub | 256 KB | Azure-native, device twins |
| HiveMQ Cloud | 256 MB | Enterprise, automotive |
| Cloudflare Pub/Sub | 1 MB | Workers integration, edge |
ESP32 MQTT CLIENT
ESP-IDF (Production)
#include "mqtt_client.h"
esp_mqtt_client_config_t cfg = {
.broker.address.uri = "mqtts://mqtt.2nth.io:8883",
.broker.verification.certificate = server_cert_pem,
.credentials.username = "device01",
.credentials.authentication.password = "secret",
.session.last_will = {
.topic = "device/status",
.msg = "{\"online\":false}",
.qos = 1, .retain = true,
},
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&cfg);
esp_mqtt_client_start(client);
// Publish telemetry
esp_mqtt_client_publish(client,
"device/telemetry",
"{\"temp\":24.5,\"heap\":280000}", 0, 0, 0);
Arduino (PubSubClient)
#include <WiFi.h>
#include <PubSubClient.h>
WiFiClient espClient;
PubSubClient mqtt(espClient);
mqtt.setServer("mqtt.2nth.io", 1883);
mqtt.connect("esp32-device", "user", "pass");
mqtt.subscribe("device/cmd");
mqtt.publish("device/telemetry", "{\"temp\":24.5}");
SECURITY
Always use TLS (port 8883) in production. Plaintext MQTT on 1883 is unacceptable for anything beyond local development.
| Method | Strength | Best For |
|---|---|---|
| Username/Password | Basic | Dev, small deploys |
| Client certs (mTLS) | Strong | Production fleet |
| JWT tokens | Strong | Cloud-native, rotating creds |
| Topic ACLs | Additive | All deployments |
For production fleets, use mTLS with per-device client certificates. Each device gets a unique cert at provisioning, and the broker ACL restricts it to its own topic subtree. This is the gold standard for IoT device auth.
SCALING PATTERNS
Bridge Pattern (Edge to Cloud)
Edge Broker (NanoMQ) Cloud Broker (EMQX)
Local devices publish Aggregated telemetry
Low-latency local rules Dashboard / API
Offline buffering Rules engine -> DB
Bridge forwards to cloud -------> Fleet management
Shared Subscriptions (v5)
# Three workers share the load — each msg to only one
Worker-1: SUBSCRIBE $share/workers/telemetry/#
Worker-2: SUBSCRIBE $share/workers/telemetry/#
Worker-3: SUBSCRIBE $share/workers/telemetry/#
Sparkplug B (Industrial)
Standardised topic namespace with birth/death certificates, Protobuf payloads, and state management for industrial IoT. Topic format: spBv1.0/{group}/{type}/{edge_node}/{device}
PAYLOAD FORMATS
| Format | Size | Schema | Best For |
|---|---|---|---|
| JSON | Baseline | Schema-less | Most IoT (human-readable) |
| CBOR | 20-40% smaller | Schema-less | Constrained devices (tinycbor) |
| Protobuf | Smallest | .proto required | Bandwidth-critical (nanopb) |
KEY GITHUB REPOSITORIES
| Repo | Purpose |
|---|---|
| eclipse/mosquitto | Reference MQTT broker (C) |
| emqx/emqx | Scalable Erlang broker |
| nanomq/nanomq | Edge-native C broker |
| espressif/esp-mqtt | ESP-IDF MQTT client |
| knolleary/pubsubclient | Arduino MQTT client |
| mqttjs/MQTT.js | Node.js / browser client |
| hivemq/hivemq-ce | Java broker (community) |