Como funciona o MQTT? Em resumo, os clientes abrem uma única conexão de longa duração com um broker, declaram quais tópicos lhes interessam, e o broker encaminha cada mensagem publicada aos assinantes correspondentes. Neste artigo você vai acompanhar esse processo pacote a pacote, da conexão TCP passando por CONNECT, SUBSCRIBE, PUBLISH, keep alive e desconexão, e reproduzir todo o trace você mesmo no servidor MQTT público.
Os três papéis: publicador, assinante e broker
O MQTT tem apenas dois tipos de participantes: clientes e brokers. Um cliente pode publicar, assinar ou fazer as duas coisas. O broker fica no meio, recebe todas as mensagens e decide quem as recebe.
- Publicadores enviam mensagens para um tópico, uma string como
plant1/line2/temperature. Eles não sabem nem se importam com quem as recebe. - Assinantes informam ao broker quais tópicos, ou padrões de tópicos, desejam. Eles não sabem quem envia.
- O broker autentica os clientes, acompanha assinaturas e sessões e roteia cada mensagem para todos os assinantes correspondentes.
Esse desacoplamento é o coração do design. Um sensor de vazão numa estação de saneamento não precisa saber o endereço IP de um painel, os dois não precisam estar online ao mesmo tempo se as sessões forem persistentes, e adicionar um quinto consumidor não exige nenhuma mudança no sensor. Para saber mais sobre a função do broker, veja o que um broker MQTT faz e, sobre o padrão em si, o modelo publish/subscribe do MQTT.
Passo 1: abrir uma conexão de rede
O MQTT roda sobre um fluxo de bytes confiável e ordenado, normalmente TCP. O cliente abre uma conexão TCP com o broker, na porta 1883 para MQTT sem criptografia ou 8883 para MQTT sobre TLS. Os navegadores, que não conseguem abrir sockets TCP brutos, transportam o MQTT dentro de um WebSocket (no ConnectMQ, portas 8083 ou 8084 com o caminho /mqtt). Até aqui nada específico do MQTT aconteceu; isto é apenas o canal.
Com TLS, ocorre agora um handshake: o cliente verifica o certificado do broker e os dois lados combinam as chaves de criptografia. Todos os pacotes MQTT seguintes são criptografados.
Passo 2: CONNECT e CONNACK
O primeiro pacote do cliente precisa ser CONNECT. Ele contém:
| Campo | Finalidade |
|---|---|
| Nome e nível do protocolo | MQTT e 4 (3.1.1) ou 5 (5.0) |
| Client ID | Identifica a sessão; deve ser único por conexão |
| Clean session / clean start | Começar do zero ou retomar uma sessão armazenada |
| Keep alive | Máximo de segundos entre pacotes do cliente |
| Usuário e senha | Credenciais opcionais |
| Last Will | Mensagem opcional que o broker publica se o cliente sumir |
| Propriedades (MQTT 5) | Session expiry, receive maximum, maximum packet size e outras |
O broker valida tudo isso e responde com CONNACK. No MQTT 5, ele contém um reason code: 0x00 para sucesso, ou um erro como credenciais inválidas, não autorizado ou, em um broker com cotas, 0x97 cota excedida. Ele também informa se uma sessão anterior foi retomada (flag session present) e pode comunicar ao cliente os limites do servidor. Até chegar um CONNACK bem-sucedido, o cliente não pode enviar mais nada.
Passo 3: SUBSCRIBE e SUBACK
Um cliente que quer receber mensagens envia SUBSCRIBE com um ou mais filtros de tópico e uma QoS solicitada para cada um. Os filtros podem conter curingas: + corresponde a exatamente um nível e # corresponde a tudo abaixo de um nível. Por exemplo, plant1/+/temperature corresponde a plant1/line2/temperature, mas não a plant1/line2/motor/temperature.
O broker responde com SUBACK, listando a QoS concedida (ou um código de falha) para cada filtro. A QoS concedida pode ser menor que a solicitada se o broker impuser um teto. Se houver mensagens retidas nos tópicos correspondentes, o broker as envia imediatamente, e é assim que um painel recém-aberto conhece o estado atual na hora.
Passo 4: PUBLISH e os handshakes de QoS
Para enviar dados, o cliente envia PUBLISH com um nome de tópico, um payload (quaisquer bytes, muitas vezes JSON), um nível de QoS e uma flag retain. O que acontece em seguida depende da QoS:
- QoS 0, no máximo uma vez. PUBLISH e pronto. Sem confirmação; se a conexão cair no momento errado, a mensagem se perde.
- QoS 1, pelo menos uma vez. O receptor responde com PUBACK. Se o remetente não o recebe, reenvia com a flag de duplicata ativada, então o receptor pode ver a mensagem duas vezes.
- QoS 2, exatamente uma vez. Uma troca em quatro etapas: PUBLISH, PUBREC, PUBREL, PUBCOMP. Mais lenta, mas sem duplicatas.
Esses handshakes acontecem salto a salto: uma vez entre o publicador e o broker e, separadamente, entre o broker e cada assinante. O broker então encaminha a mensagem a todos os clientes cujo filtro corresponde, usando a menor entre a QoS da publicação e a QoS concedida na assinatura. Todos os prós e contras estão em níveis de QoS do MQTT explicados.
Com a flag retain ativada, o broker também armazena a mensagem como o último valor conhecido daquele tópico e a entrega a futuros assinantes.
Passo 5: keep alive com PINGREQ e PINGRESP
Mesmo ocioso, o cliente precisa provar que está vivo dentro do intervalo de keep alive. Se não tiver nada para publicar, envia PINGREQ e o broker responde PINGRESP. Se o broker não receber nada por cerca de uma vez e meia o período de keep alive, considera o cliente morto, fecha a conexão e publica o Last Will do cliente, se houver um. É assim que os painéis descobrem que um dispositivo ficou offline sem que ninguém precise fazer polling.
Passo 6: DISCONNECT e sessões
Um encerramento limpo envia DISCONNECT, que diz ao broker para não publicar o Last Will. O que sobrevive depende das configurações de sessão: com clean start e sem session expiry, o broker esquece as assinaturas do cliente. Com uma sessão persistente (session expiry do MQTT 5 maior que zero), o broker mantém as assinaturas e enfileira mensagens QoS 1 e 2 até o cliente voltar ou o prazo expirar.
Reproduza o trace você mesmo
Você pode observar todo o ciclo de vida no servidor MQTT público (gratuito) em broker.connectmq.com, feito para testes e protótipos. Os clientes do Mosquitto imprimem cada pacote com -d. Escolha antes um ID aleatório único; aqui ele é q7m3x9.
# Terminal 1: assinante com saída de depuração
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-q7m3x9 -V mqttv5 -d \
-t 'connectmq/demo/q7m3x9/#' -q 1
# Terminal 2: publicador com saída de depuração
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-q7m3x9 -V mqttv5 -d \
-t 'connectmq/demo/q7m3x9/sensor/temp' -m '{"c":21.7}' -q 1
A saída do assinante fica assim (os detalhes variam conforme a versão):
Client sub-q7m3x9 sending CONNECT
Client sub-q7m3x9 received CONNACK (0)
Client sub-q7m3x9 sending SUBSCRIBE (Mid: 1, Topic: connectmq/demo/q7m3x9/#, QoS: 1, Options: 0x00)
Client sub-q7m3x9 received SUBACK
Subscribed (mid: 1): 1
Client sub-q7m3x9 received PUBLISH (d0, q1, r0, m1, 'connectmq/demo/q7m3x9/sensor/temp', ... (10 bytes))
Client sub-q7m3x9 sending PUBACK (m1, rc0)
{"c":21.7}
Client sub-q7m3x9 sending PINGREQ
Client sub-q7m3x9 received PINGRESP
E a do publicador:
Client pub-q7m3x9 sending CONNECT
Client pub-q7m3x9 received CONNACK (0)
Client pub-q7m3x9 sending PUBLISH (d0, q1, r0, m1, 'connectmq/demo/q7m3x9/sensor/temp', ... (10 bytes))
Client pub-q7m3x9 received PUBACK (Mid: 1, RC:0)
Client pub-q7m3x9 sending DISCONNECT
Leia as flags da linha PUBLISH: d0 (não é duplicata), q1 (QoS 1), r0 (não retida), m1 (identificador de pacote 1). Experimente -q 2 e você verá PUBREC, PUBREL e PUBCOMP; adicione -r ao publicador, reinicie o assinante e a mensagem retida chega logo após o SUBACK. A área pública pode ser lida por qualquer pessoa, então envie apenas dados de teste.
O mesmo fluxo em Python
As bibliotecas escondem os pacotes atrás de callbacks, mas cada um deles corresponde a um dos passos acima.
import time
import uuid
import paho.mqtt.client as mqtt
PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:6]}"
def on_connect(client, userdata, flags, reason_code, properties): # CONNACK
print("CONNACK:", reason_code)
client.subscribe(f"{PREFIX}/#", qos=1) # SUBSCRIBE
def on_subscribe(client, userdata, mid, reason_codes, properties): # SUBACK
print("SUBACK:", [str(rc) for rc in reason_codes])
client.publish(f"{PREFIX}/sensor/temp", '{"c":21.7}', qos=1) # PUBLISH
def on_publish(client, userdata, mid, reason_code, properties): # PUBACK
print("PUBACK for mid", mid)
def on_message(client, userdata, msg): # PUBLISH recebido
print("Message:", msg.topic, msg.payload.decode())
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"trace-{uuid.uuid4().hex[:8]}",
protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_publish = on_publish
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=30) # TCP + CONNECT
client.loop_start()
time.sleep(5)
client.disconnect() # DISCONNECT
client.loop_stop()
Equívocos comuns
- "O broker armazena todas as mensagens." Apenas mensagens retidas (uma por tópico) e mensagens enfileiradas para sessões persistentes. O MQTT não é um banco de dados nem um log.
- "Os tópicos precisam ser criados antes." Não, os tópicos passam a existir no momento em que alguém publica ou assina.
- "QoS 2 de ponta a ponta." A QoS vale por salto e é rebaixada para o nível da assinatura.
- "Client IDs podem ser compartilhados." Uma segunda conexão com o mesmo ID derruba a primeira.
- "O MQTT usa UDP." O MQTT padrão precisa de TCP ou de outro fluxo confiável; o MQTT-SN é a variante para UDP e redes semelhantes.
Para ir além, o tutorial de MQTT constrói um projeto completo, pacotes de controle do MQTT detalha cada tipo de pacote, e as especificações oficiais estão publicadas em mqtt.org.
Experimente o MQTT no ConnectMQ
Faça experimentos à vontade no servidor MQTT público em broker.connectmq.com (nunca com dados de produção) e, quando quiser tópicos privados e autenticados, crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito. O ConnectMQ é um broker MQTT na nuvem compatível com MQTT 3.1.1 e 5.0, com cliente no navegador e explorador de tópicos ao vivo, para que você veja em tempo real os fluxos descritos aqui. Quando passar para produção, ele funciona como um broker MQTT gerenciado.
Perguntas frequentes
Como o MQTT funciona, em termos simples?
Os dispositivos se conectam a um broker central, assinam os tópicos que lhes interessam e publicam mensagens em tópicos. O broker encaminha cada mensagem a todos os assinantes correspondentes.
Publicadores e assinantes se conectam diretamente entre si?
Não. Cada cliente se conecta apenas ao broker, e é por isso que os dispositivos nunca precisam saber os endereços uns dos outros.
O que acontece se um assinante estiver offline quando uma mensagem for publicada?
Com uma sessão persistente e QoS 1 ou 2, o broker enfileira a mensagem até o assinante se reconectar ou a sessão expirar. Caso contrário, a mensagem não é entregue a esse cliente, embora uma mensagem retida ainda lhe forneça o valor mais recente.
Qual porta o MQTT usa?
1883 para TCP sem criptografia e 8883 para TLS. As portas WebSocket variam conforme o broker; o ConnectMQ usa 8083 e 8084 com o caminho /mqtt.



