Uma sessão MQTT é o estado que broker e cliente mantêm um sobre o outro: quais tópicos o cliente assinou e quais mensagens ainda estão em trânsito. Com uma sessão persistente, esse estado sobrevive a uma desconexão, então um dispositivo que sai da rede por alguns minutos volta com as mesmas assinaturas e recebe as mensagens que perdeu. Este artigo explica como as sessões funcionam no MQTT 3.1.1 (cleanSession) e no MQTT 5 (Clean Start mais Session Expiry Interval).
O que uma sessão contém
A especificação define o estado da sessão em cada lado. No broker, ele inclui:
- A existência da própria sessão, identificada pelo client ID.
- As assinaturas do cliente (filtros de tópico e seus QoS).
- Mensagens QoS 1 e QoS 2 enviadas ao cliente, mas ainda não totalmente confirmadas.
- Mensagens QoS 1 e QoS 2 aguardando envio ao cliente — a "fila offline".
- Mensagens QoS 2 recebidas do cliente, mas ainda não totalmente confirmadas.
- Opcionalmente, mensagens QoS 0 aguardando envio (os brokers podem enfileirá-las, mas normalmente não o fazem).
O cliente guarda a sua metade: mensagens QoS 1 e 2 que ele enviou e que não foram totalmente confirmadas, e mensagens QoS 2 que recebeu e ainda não concluiu. É por isso que os níveis de QoS só cumprem suas garantias entre reconexões quando se usa uma sessão persistente.
MQTT 3.1.1: a flag cleanSession
No MQTT 3.1.1, um único bit no pacote CONNECT decide tudo:
| cleanSession | Ao conectar | Ao desconectar |
|---|---|---|
1 (true) | Qualquer sessão existente para esse client ID é descartada; uma nova começa | A sessão é apagada |
0 (false) | Uma sessão existente é retomada; caso contrário, uma nova é criada | A sessão é mantida, e as mensagens QoS 1/2 para suas assinaturas são enfileiradas |
Pelo protocolo, uma sessão persistente no 3.1.1 nunca expira sozinha. Os brokers adicionam seus próprios limites, como as opções persistent_client_expiration e max_queued_messages do Mosquitto; caso contrário, client IDs abandonados se acumulariam para sempre. Um client ID de tamanho zero só é permitido com cleanSession=1, porque uma sessão que não pode ser identificada não pode ser retomada.
MQTT 5: Clean Start e Session Expiry Interval
O MQTT 5 divide a antiga flag em dois controles independentes:
- Clean Start (uma flag) — se deve descartar qualquer sessão existente ao conectar.
- Session Expiry Interval (uma propriedade do
CONNECT, em segundos) — por quanto tempo o broker mantém a sessão depois que a conexão de rede é encerrada. Ausente ou0significa que a sessão termina junto com a conexão;0xFFFFFFFFsignifica que ela nunca expira.
Isso permite combinações que o 3.1.1 não conseguia expressar, como "sempre começar do zero, mas manter minha sessão por uma hora se eu cair" (Clean Start = 1, expiry = 3600). O cliente também pode alterar a expiração no seu pacote DISCONNECT, desde que não tenha se conectado com expiração 0.
| MQTT 3.1.1 | Configuração equivalente no MQTT 5 |
|---|---|
cleanSession = 1 | Clean Start = 1, Session Expiry Interval = 0 |
cleanSession = 0 | Clean Start = 0, Session Expiry Interval = 0xFFFFFFFF |
Brokers MQTT 5 também podem encurtar a expiração solicitada e anunciar o valor real com uma propriedade Session Expiry Interval no CONNACK. Combine isso com o Message Expiry Interval por mensagem para que comandos enfileirados não sejam entregues horas depois de terem perdido a relevância. Outras diferenças são abordadas em MQTT 5 vs 3.1.1.
A flag Session Present
O CONNACK do broker traz uma flag Session Present que informa ao cliente o que realmente aconteceu:
1— o broker encontrou e retomou uma sessão armazenada. As assinaturas continuam ativas; não é preciso assinar de novo.0— nenhuma sessão foi retomada (Clean Start estava ativado, a sessão expirou ou o broker a perdeu). O cliente precisa assinar novamente.
Clientes robustos verificam essa flag em vez de fazer suposições. O padrão simples mais seguro é assinar de novo sempre que Session Present for 0; assinar de novo quando ela é 1 é permitido, mas substitui as assinaturas existentes e pode fazer com que as mensagens retidas sejam reenviadas.
Exemplos
Na CLI do Mosquitto, -c desativa a clean session e -i define um client ID fixo — ambos são necessários para uma sessão persistente:
# 1. Create the session, then press Ctrl+C
mosquitto_sub -h broker.hivemq.com -i sensor-42-sub -c -q 1 -t 'testmqtt/sess-demo/#'
# 2. While it is offline, publish with QoS 1
mosquitto_pub -h broker.hivemq.com -q 1 -t 'testmqtt/sess-demo/cmd' -m 'reboot'
# 3. Reconnect with the same ID: the queued message is delivered
mosquitto_sub -h broker.hivemq.com -i sensor-42-sub -c -q 1 -t 'testmqtt/sess-demo/#'import mqtt from 'mqtt';
const client = mqtt.connect('wss://broker.hivemq.com:8884/mqtt', {
protocolVersion: 5,
clientId: 'sensor-42-sub',
clean: false, // Clean Start = 0
properties: { sessionExpiryInterval: 3600 },
});
client.on('connect', (connack) => {
if (!connack.sessionPresent) {
client.subscribe('testmqtt/sess-demo/#', { qos: 1 });
}
});import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
if not flags.session_present:
client.subscribe("testmqtt/sess-demo/#", qos=1)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id="sensor-42-sub", clean_session=False)
client.on_connect = on_connect
client.connect("broker.hivemq.com", 1883)
client.loop_forever()Você pode gerar código equivalente para outras linguagens com o gerador de código MQTT e usar o gerador de client ID para criar IDs estáveis e únicos. Para publicar as mensagens de teste pelo navegador, use o cliente online:
Quanto tempo uma sessão deve durar?
No MQTT 5 você precisa escolher um Session Expiry Interval, e o valor certo depende de quanto tempo o cliente pode, de forma realista, ficar fora e ainda se importar com o que perdeu:
- Apps mobile e dashboards — minutos. Tempo suficiente para sobreviver a um túnel ou a uma troca de rede, curto o bastante para que o broker não guarde estado de usuários que fecharam o app.
- Dispositivos de campo em links instáveis — de horas a um dia, de acordo com a duração típica das quedas.
- Consumidores de backend — o suficiente para cobrir uma janela de deploy ou reinício, para que nenhuma mensagem se perca enquanto a nova versão sobe.
As sessões também interagem com o Last Will. No MQTT 5, o will é publicado quando o Will Delay Interval passa ou quando a sessão termina, o que acontecer primeiro. Um will delay curto com uma sessão mais longa permite que um dispositivo se reconecte silenciosamente após uma falha breve, sem disparar um alerta de "offline".
Armadilhas comuns
- Client IDs aleatórios. Muitas bibliotecas geram um ID aleatório a cada início, o que cria silenciosamente uma nova sessão toda vez. Sessões persistentes exigem um ID estável.
- QoS 0 em algum ponto da cadeia. O QoS entregue é o menor entre o de publicação e o da assinatura. Se qualquer um for 0, as mensagens não são enfileiradas para clientes offline.
- Dois clientes com o mesmo ID. O broker desconecta o mais antigo quando o mais novo se conecta, e os dois ficam disputando a sessão. Veja erros de conexão MQTT.
- Filas sem limite. Um dispositivo que fica offline por dias pode acumular um grande backlog. Use expiração de sessão e de mensagens, além dos limites de fila do broker, para manter isso sob controle.
- Reinícios do broker. As sessões só sobrevivem a um reinício do broker se ele as persistir em disco (no Mosquitto,
persistence true).
Quando usar sessões persistentes
Use-as em dispositivos que não podem perder comandos ou atualizações de configuração, e em consumidores de backend que precisam processar toda mensagem QoS 1. Prefira clean sessions para ferramentas de curta duração, dashboards que só se importam com os valores mais recentes (as mensagens retidas cuidam disso) e qualquer coisa que se conecte com client IDs descartáveis. Em redes instáveis, combine uma sessão persistente com um intervalo de keep alive sensato, para que as desconexões sejam detectadas rapidamente e a fila assuma.
Perguntas frequentes
O que significa clean session false no MQTT?
Com cleanSession definido como false no MQTT 3.1.1, o broker mantém a sessão do cliente depois que ele se desconecta: suas assinaturas e todas as mensagens QoS 1 e QoS 2 que chegam enquanto ele está offline. Quando o cliente se reconecta com o mesmo client ID, ele retoma essa sessão e recebe as mensagens enfileiradas.
Por que não estou recebendo mensagens offline com uma sessão persistente?
Verifique quatro coisas: o cliente se reconecta exatamente com o mesmo client ID; clean session é false (ou, no MQTT 5, Clean Start é false com um Session Expiry Interval diferente de zero); tanto a assinatura quanto a publicação usam QoS 1 ou 2; e o broker não atingiu o limite de fila nem a expiração da sessão.
Qual a diferença entre Clean Session e Clean Start?
No MQTT 3.1.1, cleanSession controla tanto se uma sessão antiga é descartada ao conectar quanto se a nova sobrevive à desconexão. O MQTT 5 separa as duas coisas: Clean Start controla apenas o descarte da sessão antiga, e o Session Expiry Interval controla por quanto tempo a sessão sobrevive após a desconexão.