Fundamentos de MQTT

Sessão Persistente MQTT e a Flag Clean Session Explicadas

Uma sessão persistente permite que o broker lembre as assinaturas de um cliente e enfileire suas mensagens QoS 1 e 2 enquanto ele está offline. Saiba o que é armazenado, quando usar e quais armadilhas evitar.

Diagrama de sessão persistente MQTT mostrando um broker guardando assinaturas e mensagens enfileiradas para um dispositivo IoT desconectado
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

Uma sessão persistente MQTT permite que o broker lembre quem é um cliente, o que ele assinou e quais mensagens ainda deve entregar a ele, mesmo enquanto o cliente está desconectado. Ao final deste artigo você saberá exatamente o que o broker armazena, como a flag clean session (e sua substituta no MQTT 5) controla isso e como verificar o comportamento por conta própria com alguns comandos.

O Que É uma Sessão Persistente MQTT?

Toda conexão MQTT tem uma sessão: um pacote de estado compartilhado entre o cliente e o broker MQTT. Com uma sessão limpa (não persistente), esse estado só existe enquanto a conexão de rede durar. Desconectou, e o broker joga tudo fora. Com uma sessão persistente, o broker mantém o estado depois que a conexão fecha e o devolve quando o mesmo cliente se reconecta.

A identidade que liga a sessão antiga à nova conexão é o client ID. É por isso que sessões persistentes só funcionam quando um cliente se reconecta sempre com exatamente o mesmo ID.

O Que o Broker Armazena

Estado da sessão no broker Armazenado com sessão persistente?
As assinaturas do cliente (filtros de topic e QoS) Sim
Mensagens QoS 1 e QoS 2 que chegaram enquanto o cliente estava offline Sim
Mensagens QoS 1 e QoS 2 enviadas, mas ainda não confirmadas Sim
Mensagens QoS 2 recebidas do cliente, mas não totalmente concluídas Sim
Mensagens QoS 0 publicadas enquanto o cliente estava offline Não (os brokers podem enfileirá-las opcionalmente, a maioria não faz isso)
Retained messages Não fazem parte do estado da sessão; são armazenadas por topic para todos

O cliente guarda a sua metade: mensagens QoS 1 e 2 que enviou e que ainda não foram confirmadas, e mensagens QoS 2 que recebeu e ainda não concluiu. Uma biblioteca de cliente que mantém isso apenas em memória perde a sua metade ao reiniciar, o que é uma fonte comum de confusão.

O Que Ela Não Faz

Uma sessão persistente não é um banco de dados. Ela não armazena histórico, não reenvia mensagens que o cliente já confirmou e não entrega tráfego QoS 0 de forma confiável. Ela também só guarda mensagens de topics que o cliente já tinha assinado antes de ficar offline. Se você precisa do "último valor" de um topic independentemente de sessões, use retained messages.

A Flag Clean Session no MQTT 3.1.1

No MQTT 3.1.1 um único bit no CONNECT controla tudo:

  • cleanSession = true: descarta qualquer sessão existente, começa do zero e descarta esta sessão quando o cliente se desconecta.
  • cleanSession = false: retoma a sessão existente para este client ID, se houver uma; caso contrário, cria uma e a mantém após a desconexão.

O broker informa ao cliente o que aconteceu por meio da flag Session Present no CONNACK. Se você se conectou com cleanSession = false e o Session Present é 0, o broker não tinha estado para você, então é preciso assinar de novo. Se for 1, suas assinaturas continuam valendo e as mensagens enfileiradas estão prestes a chegar.

A fraqueza do 3.1.1 é que uma sessão persistente não tem expiração embutida. Um dispositivo desativado deixa para trás uma sessão que continua acumulando mensagens até que os limites do próprio broker entrem em ação.

Sessões Persistentes no MQTT 5

O MQTT 5 divide a flag em dois controles independentes:

  • Clean Start decide se uma sessão existente deve ser descartada no momento da conexão.
  • Session Expiry Interval decide por quanto tempo, em segundos, a sessão sobrevive após a desconexão.

Uma sessão persistente no MQTT 5 é, portanto, Clean Start = false mais um Session Expiry Interval maior que zero. O mapeamento completo, e como escolher os valores, está em clean start e session expiry interval no MQTT 5. Os brokers podem limitar a expiração que você solicita; no servidor MQTT público em broker.connectmq.com o máximo é de 30 minutos.

Teste uma Sessão Persistente MQTT Passo a Passo

Este experimento usa o servidor MQTT público, feito para testes. Escolha o seu próprio sufixo aleatório em vez de p9k2 para não colidir com outros leitores e não envie dados sensíveis, porque a área pública pode ser lida por qualquer pessoa.

  1. Inicie um assinante com ID fixo, sessão persistente e 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 desativa o clean start e -x 1800 solicita uma expiração de sessão de 30 minutos.

  1. Pare o assinante com Ctrl+C.

  2. Publique três mensagens QoS 1 enquanto ele 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
  1. Execute de novo exatamente o mesmo comando de assinante. As três mensagens chegam imediatamente, porque o broker as enfileirou na sua sessão.

  2. Repita o teste sem -c. Desta vez nada chega na reconexão: a sessão foi limpa.

O Mesmo Teste em 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:
        # O broker não tem sessão para nós: assine novamente
        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()

Verificar session_present antes de assinar é o padrão idiomático: evita assinaturas desnecessárias e se recupera corretamente quando a sessão expirou.

Quando Usar uma Sessão Persistente

Use uma quando perder uma mensagem importa e o cliente se reconecta com uma identidade estável:

  • Dispositivos que recebem comandos (abrir válvula, atualizar configuração) e podem sair da rede por pouco tempo.
  • Consumidores de backend que precisam processar todo evento QoS 1, como tratadores de alarmes.
  • Dispositivos a bateria que acordam, conectam, coletam comandos pendentes e voltam a dormir.

Prefira uma sessão limpa quando:

  • O cliente só se interessa por dados ao vivo, como um dashboard que mostra valores atuais de topics retidos.
  • Os client IDs são aleatórios ou reutilizados entre instâncias, como web workers com autoscaling.
  • Você só publica e nunca assina; há pouco estado de sessão que valha a pena guardar.

Armadilhas e Solução de Problemas

  1. Client IDs aleatórios. Muitas bibliotecas geram um ID aleatório se você o deixar vazio. Um novo ID significa uma nova sessão a cada vez, então nada é retomado. Defina um ID fixo; veja boas práticas de client ID MQTT.
  2. Assinar com QoS 0. O broker só enfileira mensagens no QoS com que você assinou. Uma assinatura QoS 0 não recebe nada enquanto está offline, mesmo que o publicador tenha usado QoS 1.
  3. Publicar com QoS 0. A entrega usa o menor entre o QoS do publish e o da assinatura. Publishes QoS 0 não são enfileirados.
  4. Esperar mensagens anteriores à primeira assinatura. Uma sessão só enfileira mensagens para as assinaturas que já tem.
  5. Enxurrada de mensagens na reconexão. Um dispositivo offline por horas pode receber uma rajada de mensagens enfileiradas. Dimensione seus buffers ou use o message expiry do MQTT 5 para que comandos obsoletos morram na fila.
  6. Reinícios do broker. O armazenamento de sessões é um detalhe de implementação de cada broker. Na ConnectMQ, as sessões ficam em memória, então sobrevivem a desconexões do cliente, mas não a um reinício do broker. Projete pensando nisso: verifique o Session Present, assine novamente quando ele for 0 e use retained messages para o estado que precisa estar sempre disponível.
  7. Limites do plano. O plano Serverless (Free) da ConnectMQ suporta QoS até 1, que é tudo de que você precisa para entrega enfileirada. O QoS 2 está disponível nos planos pagos.

Para ver mais de perto o que é enfileirado e em que quantidade, leia como o MQTT enfileira mensagens para clientes offline. É novo no protocolo? O tutorial de MQTT começa do básico.

Use Sessões Persistentes na ConnectMQ

A ConnectMQ é um broker MQTT gerenciado com suporte a MQTT 3.1.1 e 5.0, então tanto a flag clean session quanto o session expiry do MQTT 5 funcionam sem configuração adicional. Cada broker vem com credenciais geradas, e os client IDs ficam vinculados a essas credenciais, o que impede que um estranho sequestre a sessão do seu dispositivo. Cadastre-se no plano Serverless gratuito sem cartão de crédito, conecte-se com YOUR_USERNAME, YOUR_PASSWORD e YOUR_CLIENT_ID e repita o teste acima no seu próprio broker privado.

Perguntas frequentes

Uma sessão persistente MQTT armazena mensagens QoS 0?

Normalmente não. A especificação só exige o enfileiramento de mensagens QoS 1 e QoS 2; armazenar QoS 0 é opcional, e a maioria dos brokers não faz isso. Use QoS 1 para tudo o que você não pode perder.

Por que não recebo as mensagens enfileiradas depois de reconectar?

As causas mais comuns são um client ID alterado, conectar com clean session ou clean start igual a true, uma assinatura QoS 0 ou uma sessão que já expirou. Verifique a flag Session Present no CONNACK para saber se a sessão foi retomada.

Preciso assinar de novo com uma sessão persistente?

Só se o Session Present for 0. Quando o broker retoma a sua sessão, suas assinaturas já existem e você pode pular a etapa de assinatura.

As sessões persistentes sobrevivem a um reinício do broker?

Depende do broker. A ConnectMQ mantém as sessões em memória, então elas sobrevivem a desconexões do cliente, mas são apagadas se o broker reiniciar; os clientes devem tratar o Session Present = 0 de forma adequada.

Artigos relacionados

Por que Seu Cliente MQTT Fica Desconectando (e Como Corrigir)

Loops de reconexão estão entre os problemas mais comuns do MQTT. Conheça as cinco causas habituais, de client IDs duplicados a timeouts de keep alive e pacotes grandes demais, e siga um fluxo de diagnóstico que identifica a sua.

9 min de leitura

Quem Inventou o MQTT? A História dos Oleodutos à IoT

O MQTT foi inventado em 1999 por Andy Stanford-Clark, da IBM, e Arlen Nipper, da Arcom, para monitorar oleodutos via satélite. Acompanhe sua trajetória até o open source, a OASIS, a ISO e os brokers MQTT gerenciados na nuvem de hoje.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.