MQTT Retained Messages

Sometime in the past, there was a challenge to monitor oil pipelines spanning vast, remote areas. These areas had unreliable, low-bandwidth networks. Plus, the monitoring devices ran on batteries, making energy conservation essential— constant communication or high network usage wasn't practical.

A wire protocol that caters to these challenges was needed and the answer was MQTT. MQTT was designed with specific features that are tailored to the challenges at hand - features like:

  • Quality of Service (QoS)
  • Last Will and Testament
  • Retained Messages

This blog will focus on the MQTT retained messages feature and to begin…

What are MQTT retained messages?

In MQTT, when a publisher sends a message to a topic, the broker broadcasts it to all the clients subscribed to that topic. But if no clients are subscribed to the topic when a message is sent, the broker discards the message. Consequently, new or reconnecting clients will never receive the message — this is where retained messages come in.

The retained messages feature allows MQTT brokers to persist the last known message on a topic. You can enable this feature by sending a PUBLISH packet to the broker with the retain flag set to true (retain=1). When the broker sees this flag, it knows to persist the message in the topic it’s been published to. That way, new or reconnecting subscribers get that last message when they join the topic.

Because an MQTT topic can only hold one message at a time, even with retain=true the broker can only keep the latest message on that topic. For example, if you publish three messages with retain=true, the second message will override the first and third will override the second.

However, keep in mind that a retained message is not necessarily the latest value published to a topic, it is simply the most recent message with the retained flag set to true published to that topic.

In more concrete terms, let’s say you first publish message A with retain=true and next you publish message B with retain=false — even though message B is the most recent message, new and reconnecting clients subscribed to that topic would only receive message A.

Side note: Publishing a message with the retain flag set to false (retain=0) or without the retain flag at all, tells the broker to not retain the message in that topic. As a result, only clients who are currently connected and subscribed to that topic will get the message.

Now that you know what a retained message is, you are probably wondering …

Why retain a message?

  • As stated earlier, MQTT was designed to also do well in areas with unreliable networks — in such scenarios, devices connected to an MQTT broker can disconnect and reconnect unexpectedly. Retaining the last known message on a topic would allow any device coming online after a downtime to immediately get the latest message without waiting for a new update.
  • Furthermore, retained messages play a role in providing newly-subscribed clients with instant status updates upon subscribing to a topic. As a result, they don't have to wait idly for new updates from the publishers. This is particularly advantageous in scenarios where it is important to deliver real-time updates to clients.
  • You might also want to retain a message in a topic when the payload does not change very often and every new subscriber to that topic would need that same payload.

Retained messages examples

Let’s consider two examples:

  • Publishing a retained message to a topic
  • Deleting a retained message from a topic

Publishing a retained message

Most of the MQTT client libraries out there provide a super easy way to enable the retain flag. In the code snippet below we are using the MQTT.js client library where we publish a retained message by passing the retain: true flag as an option.

function pubSub() {
    const client = mqtt.connect(
        clientSettings.host, 
        clientSettings.options
    )

    client.on('connect', function () {
    console.log("[✅] Connection over channel established")
    
    client.publish('topic/temp', 'Retained Message', { retain: true }, function(err) {
        if (!err) {
        console.log('[📥] Message sent to queue');
        }
    });
    
    client.subscribe('topic/temp',  function (err) {
        if (err) {
        console.log('Could not subscribe: ', err)
        }
    });
    })

    client.on('message', function (topic, message) {
        console.log(topic)
        console.log(message.toString())
    }) 

    client.on('error', function(err) {
    console.log('ERROR: ', err);
    client.end();
    });
}

Deleting a retained message from a topic

If for whatever reason you’d like to delete a message previously retained on a topic, you can do this by explicitly publishing a zero bytes message to that topic with the retain flag set to true.

We do this by setting the payload to null in the code snippet below.

client.publish('topic/temp', null, { retain: true }, function(err) {
  if (!err) {
    console.log('[📥] Message sent to queue');
  }
});

Wrap up

As we’ve seen, by enabling messages to persist on a topic, the retain message feature ensures that new or reconnecting devices receive the last known message without delay. This is particularly valuable in scenarios where real-time information is crucial or the payload does not change frequently.

The examples provided in this blog, including how to publish and delete retained messages, highlight the ease with which this feature can be implemented using most MQTT client libraries.

Note: RabbitMQ supports MQTT 3.1.1 in all its versions as well as MQTT 5.0 in versions >= 3.13. You can create a free RabbitMQ instance on CloudAMQP and test out MQTT.

We’d be happy to hear from you! Please leave your suggestions, questions, or feedback in the comment section or contact us at contact@cloudamqp.com

CloudAMQP - industry leading RabbitMQ as a service

Start your managed cluster today. CloudAMQP is 100% free to try.

13,000+ users including these smart companies