Normalmente, un broker MQTT reenvía un mensaje a los clientes suscritos en ese momento y después lo olvida. Un cliente que se suscribe un minuto más tarde no ve nada hasta la siguiente publicación. Los mensajes retenidos (retained) resuelven esto: el broker guarda el último mensaje retenido de un topic y se lo entrega de inmediato a cada nuevo suscriptor, de modo que siempre empiezan con el estado actual.
Cómo funcionan los mensajes retenidos
La retención se controla con un único bit, el flag RETAIN del paquete PUBLISH. Cuando el broker recibe una publicación con RETAIN=1:
- Entrega el mensaje a los suscriptores actuales, como siempre.
- Guarda el mensaje (topic, payload, QoS) como mensaje retenido de ese topic, sustituyendo al anterior si lo hubiera. Hay como máximo un mensaje retenido por topic.
- Cada vez que un cliente se suscribe más adelante con un filtro que coincide con el topic, el broker envía el mensaje retenido justo después del
SUBACK, con el flag retain activado para que el cliente sepa que es un valor almacenado.
10:00 device PUBLISH acme/th-01/setpoint "21.0" retain=1 -> broker stores it
10:05 device PUBLISH acme/th-01/setpoint "22.5" retain=1 -> replaces "21.0"
10:30 app SUBSCRIBE acme/+/setpoint
10:30 broker PUBLISH acme/th-01/setpoint "22.5" retain=1 -> delivered instantlyLas suscripciones con comodines reciben los mensajes retenidos de todos los topics que coinciden; así es como un dashboard suscrito a acme/+/status puede pintar el estado de todos los dispositivos nada más arrancar.
El flag retain en la entrega
En MQTT 3.1.1, un mensaje reenviado a un suscriptor existente siempre lleva el flag retain desactivado; el flag solo se activa cuando el mensaje se envía por una nueva suscripción. MQTT 5 mantiene ese comportamiento por defecto, pero añade la opción de suscripción Retain As Published, que conserva el flag original: útil para bridges.
Sin retención, un dashboard recién arrancado mostraría casillas vacías hasta que cada dispositivo volviera a publicar, lo que en el caso de un sensor de puerta o un valor de configuración podría tardar horas. Con retención, la primera pantalla ya es correcta.
Cuándo usar mensajes retenidos
- Estado del dispositivo:
online/offline, encendido/apagado, modo actual. - Configuración y consignas: un dispositivo que se reinicia se suscribe y recibe al instante su configuración.
- Valores que cambian poco: versión de firmware, ubicación, última lectura conocida.
- Presencia, junto con un mensaje Last Will retenido, para que el estado offline persista.
Evita retener:
- Eventos y comandos: un comando
unlock-doorretenido se reenviaría a cada nuevo suscriptor, quizá días después. - Flujos de alta frecuencia: retener no hace daño, pero no tiene sentido si el siguiente valor llega en un segundo.
- Topics por mensaje: los topics que contienen IDs o marcas de tiempo dejan atrás miles de mensajes retenidos obsoletos.
Cómo borrar un mensaje retenido
Para eliminar un mensaje retenido, publica en el mismo topic con el flag retain activado y un payload de longitud cero. El broker borra el mensaje almacenado y no guarda el vacío. Los suscriptores actuales sí reciben el mensaje vacío, así que haz que tu código ignore los payloads vacíos.
# -r = retain, -n = send a null (zero-length) payload
mosquitto_pub -h broker.hivemq.com -t 'testmqtt/demo/status' -r -nclient.publish('testmqtt/demo/status', '', { retain: true, qos: 1 });Para borrar muchos topics a la vez, suscríbete con un comodín, recopila todos los topics que entreguen un mensaje con el flag retain y publica un payload retenido vacío en cada uno. No existe un comando estándar para «borrar todos los retenidos»: algunos brokers ofrecen herramientas de administración, pero son específicas de cada broker.
Mensajes retenidos vs sesiones persistentes
Los mensajes retenidos se confunden a menudo con las sesiones persistentes, pero responden a preguntas distintas:
| Mensaje retenido | Sesión persistente | |
|---|---|---|
| Ámbito | Por topic, compartido por todos los suscriptores | Por client ID |
| Qué se guarda | Solo el último mensaje | Las suscripciones y todos los mensajes QoS 1/2 perdidos |
| Quién lo recibe | Cualquier cliente que se suscriba después | Solo ese cliente cuando se reconecta |
| Uso típico | Estado actual | No perder eventos |
Un dispositivo que necesita tanto su configuración actual como todos los comandos enviados mientras estaba offline usa ambos: un topic de configuración retenido y una sesión persistente para el topic de comandos. La guía de QoS explica cómo interactúan las sesiones y el QoS.
Los mensajes retenidos también conservan su QoS. Cuando el broker entrega un mensaje almacenado a un nuevo suscriptor, se aplica la regla de degradación habitual: el suscriptor lo recibe con el menor entre el QoS original y el QoS de su suscripción.
Mensajes retenidos en MQTT 5
MQTT 5 añade un control más fino sobre los mensajes retenidos:
| Funcionalidad | Qué hace |
|---|---|
| Retain Handling (opción de suscripción) | 0 = enviar los mensajes retenidos al suscribirse (por defecto), 1 = solo si la suscripción es nueva, 2 = no enviarlos nunca |
| Retain As Published (opción de suscripción) | Conserva el flag retain original en los mensajes reenviados |
| Message Expiry Interval (propiedad de publicación) | El broker descarta el mensaje retenido tras el número de segundos indicado |
| Retain Available (propiedad del CONNACK) | Indica al cliente si el broker soporta mensajes retenidos |
La caducidad de mensajes es especialmente práctica: una lectura de sensor retenida que caduca al cabo de una hora nunca puede confundirse con una reciente. Consulta MQTT 5 vs 3.1.1 para ver la lista completa de cambios.
Prueba los mensajes retenidos
- Publica
onlinecon Retain marcado entestmqtt/your-id/status. - Desconéctate, vuelve a conectarte y suscríbete a
testmqtt/your-id/#. El mensaje llega al instante, marcado como retenido. - Publica un payload vacío con Retain marcado y vuelve a suscribirte: no llega nada. El mensaje retenido ha desaparecido.
Pruébalo en el cliente MQTT online
El cliente MQTT online muestra una etiqueta de retenido en los mensajes almacenados, lo que facilita detectar estados obsoletos. Para una checklist más amplia, consulta cómo probar un broker MQTT.
Preguntas frecuentes
¿Cómo borro un mensaje retenido en MQTT?
Publica en el mismo topic un mensaje con el flag retain activado y un payload de longitud cero (vacío). El broker elimina el mensaje retenido almacenado y no guarda el mensaje vacío. Con mosquitto_pub, usa -r -n.
¿Cuántos mensajes retenidos puede tener un topic?
Uno. El broker guarda solo el mensaje retenido más reciente de cada topic; cada nueva publicación retenida sustituye a la anterior.
¿Un mensaje retenido es lo mismo que una sesión persistente?
No. Un mensaje retenido es el último valor de un topic y se entrega a cualquier nuevo suscriptor. Una sesión persistente pone en cola mensajes para un cliente concreto mientras está offline. Resuelven problemas distintos y a menudo se usan juntos.