Una sesión persistente MQTT permite al broker recordar quién es un cliente, a qué se ha suscrito y qué mensajes le debe todavía, incluso mientras el cliente está desconectado. Al terminar este artículo sabrás exactamente qué almacena el broker, cómo lo controla el flag clean session (y su sustituto en MQTT 5) y cómo comprobar tú mismo el comportamiento con unos pocos comandos.
¿Qué es una sesión persistente MQTT?
Toda conexión MQTT tiene una sesión: un conjunto de estado compartido entre el cliente y el broker MQTT. Con una sesión limpia (no persistente), ese estado solo dura lo que dura la conexión de red. Al desconectarte, el broker lo descarta todo. Con una sesión persistente, el broker conserva el estado tras cerrarse la conexión y lo devuelve cuando el mismo cliente se reconecta.
La identidad que vincula la sesión antigua con la nueva conexión es el client ID. Por eso las sesiones persistentes solo funcionan cuando un cliente se reconecta siempre con exactamente el mismo ID.
Qué almacena el broker
| Estado de sesión en el broker | ¿Se guarda con sesión persistente? |
|---|---|
| Las suscripciones del cliente (filtros de topic y QoS) | Sí |
| Mensajes QoS 1 y QoS 2 que llegaron mientras el cliente estaba offline | Sí |
| Mensajes QoS 1 y QoS 2 enviados pero aún sin confirmar | Sí |
| Mensajes QoS 2 recibidos del cliente pero no completados del todo | Sí |
| Mensajes QoS 0 publicados mientras el cliente estaba offline | No (los brokers pueden encolarlos opcionalmente; la mayoría no lo hace) |
| Mensajes retenidos | No son estado de sesión; se guardan por topic para todos |
El cliente conserva su propia mitad: los mensajes QoS 1 y 2 que envió y aún no se han confirmado, y los mensajes QoS 2 que recibió pero todavía no ha completado. Una librería cliente que guarde esto solo en memoria perderá su mitad al reiniciarse, lo que es una fuente habitual de confusión.
Lo que no hace
Una sesión persistente no es una base de datos. No guarda historial, no vuelve a enviar mensajes que el cliente ya ha confirmado y no entrega de forma fiable el tráfico QoS 0. Además, solo retiene mensajes de topics a los que el cliente ya estaba suscrito antes de quedarse offline. Si necesitas el "último valor" de un topic independientemente de las sesiones, usa mensajes retenidos.
El flag clean session en MQTT 3.1.1
En MQTT 3.1.1, un único bit del CONNECT lo controla todo:
- cleanSession = true: descarta cualquier sesión existente, empieza de cero y descarta esta sesión cuando el cliente se desconecta.
- cleanSession = false: reanuda la sesión existente para este client ID si la hay; si no, crea una y la conserva tras la desconexión.
El broker indica al cliente lo que ha ocurrido mediante el flag Session Present del CONNACK. Si te conectaste con cleanSession = false y Session Present vale 0, el broker no tenía estado para ti, así que debes volver a suscribirte. Si vale 1, tus suscripciones siguen activas y los mensajes encolados están a punto de llegar.
El punto débil de 3.1.1 es que una sesión persistente no tiene caducidad integrada. Un dispositivo dado de baja deja tras de sí una sesión que sigue acumulando mensajes hasta que entran en juego los límites del propio broker.
Sesiones persistentes en MQTT 5
MQTT 5 divide el flag en dos controles independientes:
- Clean Start decide si se descarta una sesión existente en el momento de conectar.
- Session Expiry Interval decide cuánto tiempo sobrevive la sesión tras la desconexión, en segundos.
Por tanto, una sesión persistente en MQTT 5 es Clean Start = false más un Session Expiry Interval mayor que cero. La correspondencia completa, y cómo elegir los valores, se explica en clean start y session expiry interval en MQTT 5. Los brokers pueden limitar la caducidad que solicitas; en el servidor MQTT público gratuito broker.connectmq.com, el máximo es de 30 minutos.
Prueba una sesión persistente MQTT paso a paso
Este experimento usa ese mismo servidor público. Elige tu propio sufijo aleatorio en lugar de p9k2 para no chocar con otros lectores, y no envíes datos sensibles, porque cualquiera puede leer el área pública.
- Inicia un suscriptor con un ID fijo, una sesión persistente y QoS 1:
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
-i persist-demo-p9k2 -c -x 1800 -q 1 -v \
-t 'connectmq/demo/p9k2/alerts'
-c desactiva clean start y -x 1800 solicita una caducidad de sesión de 30 minutos.
Detén el suscriptor con Ctrl+C.
Publica tres mensajes QoS 1 mientras está offline:
for i in 1 2 3; do
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-p9k2 \
-q 1 -t 'connectmq/demo/p9k2/alerts' -m "alert $i"
done
Ejecuta de nuevo exactamente el mismo comando del suscriptor. Los tres mensajes llegan de inmediato, porque el broker los encoló en tu sesión.
Repite la prueba sin
-c. Esta vez no llega nada al reconectar: la sesión se limpió.
La misma prueba en Python
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes
TOPIC = "connectmq/demo/p9k2/alerts"
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code, "session present:", flags.session_present)
if not flags.session_present:
# El broker no tiene sesión para nosotros: volvemos a suscribirnos
client.subscribe(TOPIC, qos=1)
def on_message(client, userdata, msg):
print(msg.topic, msg.payload.decode())
client = mqtt.Client(
mqtt.CallbackAPIVersion.VERSION2,
client_id="persist-py-p9k2",
protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_message = on_message
props = Properties(PacketTypes.CONNECT)
props.SessionExpiryInterval = 1800 # segundos
client.connect("broker.connectmq.com", 1883, keepalive=60,
clean_start=False, properties=props)
client.loop_forever()
Comprobar session_present antes de suscribirse es el patrón idiomático: evita suscripciones innecesarias y se recupera correctamente cuando la sesión ha caducado.
Cuándo usar una sesión persistente
Úsala cuando perder un mensaje importe y el cliente se reconecte con una identidad estable:
- Dispositivos que reciben comandos (abrir una válvula, actualizar la configuración) y pueden desconectarse de la red brevemente.
- Consumidores backend que deben procesar todos los eventos QoS 1, como los gestores de alarmas.
- Dispositivos con batería que despiertan, se conectan, recogen los comandos pendientes y vuelven a dormir.
Prefiere una sesión limpia cuando:
- Al cliente solo le interesan los datos en directo, como un dashboard que muestra valores actuales a partir de topics retenidos.
- Los client IDs son aleatorios o se reutilizan entre instancias, como en workers web con autoescalado.
- Solo publicas y nunca te suscribes; apenas hay estado de sesión que merezca la pena conservar.
Errores comunes y resolución de problemas
- Client IDs aleatorios. Muchas librerías generan un ID aleatorio si lo dejas vacío. Un ID nuevo implica una sesión nueva cada vez, así que nunca se reanuda nada. Fija un ID; consulta las buenas prácticas del client ID de MQTT.
- Suscribirse con QoS 0. El broker solo encola mensajes con el QoS con el que te suscribiste. Una suscripción QoS 0 no recibe nada mientras está offline, aunque el publicador haya usado QoS 1.
- Publicar con QoS 0. La entrega usa el menor entre el QoS de publicación y el de suscripción. Las publicaciones QoS 0 no se encolan.
- Esperar mensajes anteriores a la primera suscripción. Una sesión solo encola mensajes para las suscripciones que ya tiene.
- Avalanchas de la sesión al reconectar. Un dispositivo que lleva horas offline puede recibir una ráfaga de mensajes encolados. Dimensiona tus buffers o usa la caducidad de mensajes de MQTT 5 para que los comandos obsoletos mueran en la cola.
- Reinicios del broker. El almacenamiento de sesiones es un detalle de implementación de cada broker. En ConnectMQ, las sesiones se guardan en memoria, así que sobreviven a las desconexiones de los clientes pero no a un reinicio del broker. Diseña teniéndolo en cuenta: comprueba Session Present y vuelve a suscribirte cuando valga 0, y usa mensajes retenidos para el estado que deba estar siempre disponible.
- Límites del plan. El plan Serverless (Free) de ConnectMQ admite QoS hasta 1, que es todo lo que necesitas para la entrega encolada. QoS 2 está disponible en los planes de pago.
Para ver con más detalle qué se encola y en qué cantidad, lee cómo encola MQTT los mensajes para clientes offline. ¿Eres nuevo en el protocolo? El tutorial de MQTT empieza desde lo básico.
Usa sesiones persistentes en ConnectMQ
ConnectMQ es un broker MQTT gestionado compatible con MQTT 3.1.1 y 5.0, así que tanto el flag clean session como la caducidad de sesión de MQTT 5 funcionan desde el primer momento. Cada broker incluye credenciales generadas, y los client IDs están vinculados a esas credenciales, lo que impide que un desconocido secuestre la sesión de tu dispositivo. Regístrate en el plan Serverless gratuito sin tarjeta de crédito, conéctate con YOUR_USERNAME, YOUR_PASSWORD y YOUR_CLIENT_ID, y repite la prueba anterior en tu propio broker privado.
Preguntas frecuentes
¿Una sesión persistente MQTT almacena mensajes QoS 0?
Normalmente no. La especificación solo exige encolar los mensajes QoS 1 y QoS 2; almacenar QoS 0 es opcional y la mayoría de los brokers no lo hacen. Usa QoS 1 para todo lo que no te puedas permitir perder.
¿Por qué no recibo los mensajes encolados tras reconectar?
Las causas más habituales son un client ID distinto, conectarse con clean session o clean start a true, una suscripción QoS 0 o una sesión que ya ha caducado. Comprueba el flag Session Present del CONNACK para saber si la sesión se reanudó.
¿Tengo que volver a suscribirme con una sesión persistente?
Solo si Session Present vale 0. Cuando el broker reanuda tu sesión, tus suscripciones ya existen y puedes omitir la suscripción.
¿Sobreviven las sesiones persistentes a un reinicio del broker?
Depende del broker. ConnectMQ guarda las sesiones en memoria, así que sobreviven a las desconexiones de los clientes pero se borran si el broker se reinicia; los clientes deben gestionar con elegancia Session Present = 0.



