MESSAGING GUIDE · UPDATED 11 AUG 2026

MQTT: the language of devices

Vending machines in metro stations, visi-coolers in kirana stores, chargers in parking garages — devices on SIM cards with signal that comes and goes. MQTT is built for exactly that world, and it rewards designs that respect its constraints.

Why MQTT for device fleets

A vending machine on a 2G fallback connection cannot afford HTTP’s handshake overhead per reading. MQTT keeps one lightweight persistent connection, publishes on kilobyte-scale topics, and — critically — the broker knows the moment a device disconnects. That connection-state awareness, via keep-alive and Last Will messages, is what turns a fleet dashboard from a guess into a fact.

Topic design as API design

  • Hierarchical and predictable: vending/{machineId}/telemetry/stock, ev/{chargerId}/status — wildcards let services subscribe to exactly their slice.
  • Devices publish narrow, subscribe narrower: a machine sees only its own command topic — per-device ACLs enforced at the broker.
  • Retained messages for last-known state: a dashboard connecting at 3 a.m. gets every device’s status instantly, no polling.
  • Version topics from day one: v1/vending/... — 2000 field devices do not upgrade on your schedule.

QoS, honestly applied

  • QoS 0 for high-frequency telemetry — losing one temperature reading of 60 per hour is nothing.
  • QoS 1 for transactions and commands — delivery guaranteed, consumers deduplicate (the vending sale must arrive; it must not arrive twice as two sales).
  • QoS 2 almost never — the handshake cost rarely justifies it when idempotent consumers make QoS 1 sufficient.
  • Last Will on every device: broker publishes offline the moment a machine vanishes — field-service dispatch runs on this signal.

Worked example: device contract and platform subscriber

A vending machine’s complete topic contract, and the platform side subscribing with MQTTnet — note the Last Will doing the fleet-status heavy lifting:

# Device publishes                          QoS
v1/vending/VM-2041/telemetry/stock          0     every 15 min
v1/vending/VM-2041/transaction              1     on each vend
v1/vending/VM-2041/status                   1     retained: "online"
# Broker publishes on unclean disconnect (Last Will)
v1/vending/VM-2041/status                   1     retained: "offline"
# Device subscribes (its slice only, enforced by ACL)
v1/vending/VM-2041/command/#

// Platform subscriber
var opts = new MqttClientOptionsBuilder()
    .WithTcpServer("broker.internal", 8883).WithTlsOptions(o => o.Build())
    .WithCredentials("ingest-svc", secret)
    .Build();
await client.SubscribeAsync("v1/vending/+/transaction", MqttQualityOfServiceLevel.AtLeastOnce);
client.ApplicationMessageReceivedAsync += e =>
    _ingest.EnqueueAsync(e.ApplicationMessage.Topic, e.ApplicationMessage.Payload);

FAQ

MQTT vs HTTP for IoT?

MQTT for anything with a persistent device population: lower overhead, real connection state, and server-push commands. HTTP still fine for firmware downloads and bulk uploads over the side channel.

Which broker in production?

EMQX and Mosquitto have both served me well — EMQX for large fleets needing clustering and per-device auth at scale, Mosquitto for lean single-node deployments. Managed options (AWS IoT Core) trade control for zero ops.

How does MQTT relate to OCPP?

OCPP runs over WebSocket, not MQTT — but the fleet-management lessons (connection state, offline queuing, command patterns) transfer directly. My platforms run both: OCPP for chargers, MQTT for vending and sensor fleets.