How to implement MQTT on a microcontroller

This fresh look at IoT communication and security design goes beyond a typical MQTT setup. The post How to implement MQTT on a microcontroller appeared first on EDN.

How to implement MQTT on a microcontroller

One of the original and most important reasons Message Queuing Telemetry Transport (MQTT) became the de facto protocol for Internet of Things (IoT) is its ability to connect and control devices that are not directly reachable over the Internet.

In this article, we’ll discuss MQTT in an unconventional way. Why does it exist at all? Why is it popular? If you’re about to implement a device management system, is MQTT the best fit, or are there better alternatives?

Figure 1 This is how incoming connections are blocked. Source: Cesanta Software

In real networks—homes, offices, factories, and cellular networks—devices typically sit behind routers, network address translation (NAT) gateways, or firewalls. These barriers block incoming connections, which makes traditional client/server communication impractical (Figure 1).

However, as shown in the figure below, even the most restrictive firewalls usually allow outgoing TCP connections.

Figure 2 Even the most restrictive firewalls usually allow outgoing TCP connections. Source: Cesanta Software

MQTT takes advantage of this: instead of requiring the cloud or the user to initiate a connection into the device, the device initiates an outbound connection to a publicly visible MQTT broker. Once this outbound connection is established, the broker becomes a communication hub, enabling control, telemetry, and messaging in both directions.

Figure 3 This is how devices connect out but servers never connect in. Source: Cesanta Software

This simple idea—devices connect out, servers never connect in—solves one of the hardest networking problems in IoT: how to reach devices that you cannot address directly.

To summarize:

  • The device opens a long-lived outbound TCP connection to the broker.
  • Firewalls/NAT allow outbound connections, and they maintain the state.
  • The broker becomes the “rendezvous point” accessible to all.
  • The server or user publishes messages to the broker; the device receives them over its already-open connection.

Publish/subscribe

Every MQTT message is carried inside a binary frame with a very small header, typically only a few bytes. These headers contain a command code—called a control packet type—that defines the semantic meaning of the frame. MQTT defines only a handful of these commands, including:

  • CONNECT: The client initiates a session with the broker.
  • PUBLISH: It sends a message to a named topic.
  • SUBSCRIBE: It registers interest in one or more topics.
  • PINGREQ/PINGRESP: They keep alive messages to maintain the connection.
  • DISCONNECT: It ends the session cleanly.

Because the headers are small and fixed in structure, parsing them on a microcontroller (MCU) is fast and predictable. The payload that follows these headers can be arbitrary data, from sensor readings to structured messages.

So, the publish/subscribe pattern works like this: a device publishes a message to a topic (a string such as factory/line1/temp). Other devices subscribe to topics they care about. The broker delivers messages to all subscribers of each topic.

Figure 4 The model shows decoupling of senders and receivers. Source: Cesanta Software

As shown above, the model decouples senders and receivers in three important ways:

  • In time: Publishers and subscribers do not need to be online simultaneously.
  • In space: Devices never need to know each other’s IP addresses.
  • In message flow: Many-to-many communication is natural and scalable.

For small IoT devices, the publish/subscribe model removes networking complexity while enabling structured, flexible communication. Combined with MQTT’s minimal framing overhead, it achieves reliable messaging even on low-bandwidth or intermittent links.

Request/response over MQTT

MQTT was originally designed as a broadcast-style protocol, where devices publish telemetry to shared topics and any number of subscribers can listen. This publish/subscribe model is ideal for sensor networks, dashboards, and large-scale IoT systems where data fan-out is needed. However, MQTT can also support more traditional request/response interactions—similar to calling an API—by using a simple topic-based convention.

To implement request/response, each device is assigned two unique topics, typically embedding the device ID:

Request topic (RX): devices/DEVICE_ID/rx used by the server or controller to send a command to the device.

Response topic (TX): devices/DEVICE_ID/tx used by the device to send results back to the requester.

When the device receives a message on its RX topic, it interprets the payload as a command, performs the corresponding action, and publishes the response on its TX topic. Because MQTT connections are persistent and outbound from the device, this pattern works even for devices behind NAT or firewalls.

This structure effectively recreates a lightweight RPC-style workflow over MQTT. The controller sends a request to a specific device’s RX topic; the device executes the task and publishes a response to its TX topic. The simplicity of topic naming allows the system to scale cleanly to thousands or millions of devices while maintaining separation and addressing.

With it, it’s easy to implement remote device control using MQTT. One of the practical choices is to use JSON-RPC for the request/response.

Secure connectivity

MQTT includes basic authentication features such as username/password and transport layer security (TLS) encryption, but the protocol itself offers very limited isolation between clients. Once a client is authenticated, it can typically subscribe to wildcard topics and receive all messages published on the broker. Also, it can publish to any topic, potentially interfering with other devices.

Because MQTT does not define fine-grained access control in its standard, many vendors implement non-standard extensions to ensure proper security boundaries. For example, AWS IoT attaches per-client access control lists (ACLs) tied to X.509 certificates, restricting exactly which topics a device may publish or subscribe to. Similar policy frameworks exist in EMQX, HiveMQ, and other enterprise brokers.

In practice, production systems must rely on these vendor-specific mechanisms to enforce strong authorization and prevent devices from accessing each other’s data.

MQTT implementation on a microcontroller

MCUs are ideal MQTT clients because the protocol is lightweight and designed for low-bandwidth, low-RAM environments. Implementing MQTT on an MCU typically involves integrating three components: a TCP/IP stack (Wi-Fi, Ethernet, or cellular), an MQTT library, and application logic that handles commands and telemetry.

After establishing a network connection, the device opens a persistent outbound TCP session to an MQTT broker and exchanges MQTT frames—CONNECT, PUBLISH, and SUBSCRIBE—using only a few kilobytes of memory. Most implementations follow an event-driven model: the device subscribes to its command topic, publishes telemetry periodically, and maintains the connection with periodic ping messages. With this structure, even small MCUs can participate reliably in large-scale IoT systems.

An example of a fully functional but tiny MQTT client can be found in the Mongoose repository: mqtt-client.

WebSocket server: An alternative

If all you need is a clean way for your devices to talk to your back-end, MQTT can feel like bringing a whole toolbox just to tighten one screw. JSON-RPC over WebSocket keeps things minimal: devices open a WebSocket, send tiny JSON-RPC method calls, and get direct responses. No brokers, no topic trees, and no QoS semantics to wrangle.

The nice part is how naturally it fits into a modern back-end. The same service handling the WebSocket connections can also expose a familiar REST API. That REST layer becomes the human- and script-friendly interface, while JSON-RPC over WebSocket stays as the fast “device side” protocol.

The back-end basically acts as a bridge: REST in, RPC out. This gives you all the advantages of REST—a massive ecosystem of tools, gateways, authentication systems, monitoring, and automation—without forcing your devices to speak.

Figure 5 This is how REST to JSON-RPC over WebSocket bridge architecture looks like. Source: Cesanta Software

This setup also avoids one of MQTT’s classic security footguns, where a single authenticated client can accidentally gain visibility or access to messages from the entire fleet just by subscribing to the wrong topic pattern.

With a REST/WebSocket bridge, every device connection is isolated, and authentication happens through well-understood web mechanisms like JWTs, mTLS, API keys, OAuth, or whatever your infrastructure already supports. It’s a much more natural fit for modern access control models.

Beyond typical MQTT setup

This article offers a fresh look at IoT communication, going beyond the typical MQTT setup. It explains why MQTT is great for devices behind NAT/firewalls (devices only connect out to the broker) and highlights that the protocol’s lack of fine-grained access control can create security headaches. It also outlines an alternative solution: JSON-RPC over a single persistent WebSocket connection.

For a practical application demo of these MQTT principles, see the video tutorial that explains how to implement an MQTT client on an MCU and build a web UI that displays MQTT connection status, provides connect/disconnect control, and lets you publish MQTT messages to any topic.

In this step-by-step tutorial, we use STM32 Nucleo-F756ZG development board with Mongoose Wizard—though the same method applies to virtually any other MCU platform—and a free HiveMQ Public Broker. This tutorial is suitable for anyone working with embedded systems, IoT devices, or STM32 development stack, and looking to integrate MQTT networking and a lightweight web UI dashboard into their firmware.

Sergey Lyubka is co-founder and technical director of Cesanta Software Ltd. He is known as the author of the open-source Mongoose Embedded Web Server and Networking Library (https://mongoose.ws), which has been on the market since 2004 and has over 12k stars on GitHub.

Related Content

The post How to implement MQTT on a microcontroller appeared first on EDN.

What's Your Reaction?

like

dislike

love

funny

angry

sad

wow