O MQTT 5 é a versão atual do padrão MQTT e resolve muitos dos problemas que as equipes enfrentam ao rodar MQTT 3.1.1 em produção. Neste guia você vai descobrir quais recursos do MQTT 5 realmente mudam o trabalho de engenharia do dia a dia, compará-los lado a lado com o 3.1.1 e testá-los você mesmo no servidor MQTT público broker.connectmq.com com as ferramentas de CLI do Mosquitto e Python.
Se você é novo no protocolo, comece por o que é um broker MQTT e volte aqui depois.
Por Que o MQTT 5 Existe
O MQTT 3.1.1 é pequeno, estável e está em todo lugar. Mas ele deixa perguntas importantes sem resposta. Por que minha conexão foi recusada? Por que minha assinatura falhou? Como distribuo as mensagens de um topic entre vários workers? Por quanto tempo o broker deve manter minha sessão ou um comando antigo?
No 3.1.1, as respostas geralmente eram "o broker fechou o socket" ou "escreva isso você mesmo no payload". O MQTT 5, padronizado pela OASIS em 2019, adiciona ao protocolo retorno explícito, metadados e limites, mantendo o mesmo modelo publish/subscribe. Seus topics, níveis de QoS e retained messages funcionam exatamente como antes. A especificação completa está disponível na OASIS.
MQTT 3.1.1 vs MQTT 5 em Resumo
| Recurso | MQTT 3.1.1 | MQTT 5 |
|---|---|---|
| Retorno de erros | Alguns return codes no CONNACK, flag de falha no SUBACK | Reason codes em quase todas as confirmações, mais reason strings opcionais |
| Duração da sessão | Clean session liga ou desliga | Session Expiry Interval em segundos |
| Duração da mensagem | Ilimitada até ser entregue | Message Expiry Interval por mensagem |
| Balanceamento de carga | Fora do padrão | Shared subscriptions $share/{group}/{filter} |
| Economia de banda | Topic completo em cada PUBLISH | Topic aliases (um inteiro no lugar da string do topic) |
| Metadados personalizados | Só dentro do payload | User properties (pares chave/valor) |
| Request/response | Convenções improvisadas | Response Topic e Correlation Data |
| Controle de fluxo | Específico de cada implementação | Receive Maximum negociado em CONNECT/CONNACK |
| Limites do servidor | O cliente precisa adivinhar | Anunciados no CONNACK (Maximum QoS, Retain Available e outros) |
Reason Codes: Saber Por Que Algo Falhou
A mudança mais útil do MQTT 5 para a operação são os reason codes. CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK e DISCONNECT carregam um código de um byte, e o servidor pode enviar junto uma reason string legível por humanos.
| Código | Nome | Significado típico |
|---|---|---|
| 0x00 | Success | Operação aceita |
| 0x10 | No matching subscribers | Publicação QoS 1/2 aceita, mas ninguém está assinando |
| 0x86 | Bad user name or password | Credenciais incorretas |
| 0x87 | Not authorized | O cliente não tem permissão para a ação |
| 0x89 | Server busy | O broker está se protegendo, tente mais tarde |
| 0x95 | Packet too large | A mensagem excede o tamanho máximo de pacote |
| 0x97 | Quota exceeded | Um limite de taxa ou de uso foi atingido |
Códigos abaixo de 0x80 indicam sucesso; 0x80 e acima são falhas. Para dispositivos em campo, isso faz muita diferença: o firmware pode reagir de um jeito a "senha errada" (parar e alertar) e de outro a "servidor ocupado" (recuar e tentar de novo). O ConnectMQ retorna reason codes como 0x97 Quota exceeded e 0x89 Server busy, para que seus clientes consigam distinguir um problema de cota de uma sobrecarga temporária.
Session Expiry e Message Expiry
Session Expiry Interval
No 3.1.1, uma sessão persistente (clean session = false) dura até o cliente voltar, possivelmente para sempre. O MQTT 5 substitui isso por duas configurações: Clean Start (começar do zero ou retomar) e Session Expiry Interval (por quantos segundos o broker mantém a sessão após a desconexão). Um sensor que dorme por dez minutos pode pedir uma sessão de 15 minutos e ainda receber suas mensagens QoS 1 enfileiradas ao acordar, enquanto sessões abandonadas desaparecem sozinhas.
No ConnectMQ, o session expiry tem um teto por plano; no servidor MQTT público, o máximo é 30 minutos.
Message Expiry Interval
O publisher pode anexar a cada mensagem uma validade em segundos. Se a mensagem ainda estiver esperando em uma fila ou armazenada como retida quando o intervalo acabar, o broker a descarta. É exatamente o que você quer para comandos como "abrir a válvula", que são perigosos se executados uma hora depois.
mosquitto_pub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-pub \
-t "connectmq/demo/a1b2/commands/valve1" -m "open" -q 1 \
-D publish message-expiry-interval 60
Shared Subscriptions: Balanceamento de Carga Nativo
Com uma assinatura normal, cada subscriber recebe todas as mensagens. Isso vira um problema quando uma única instância de backend não dá conta de milhares de dispositivos. As shared subscriptions do MQTT 5 permitem que vários clientes entrem em um grupo; o broker entrega cada mensagem a apenas um membro do grupo.
A sintaxe é $share/{group}/{filter}. Os publishers não mudam nada: continuam publicando no topic simples.
Teste: Dois Workers Compartilhando um Topic
Abra dois terminais e inicie dois consumidores no mesmo grupo workers. Troque a1b2 pelo seu próprio ID aleatório, porque a área pública pode ser lida por todos.
# Terminal 1
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-w1 \
-t '$share/workers/connectmq/demo/a1b2/jobs' -v
# Terminal 2
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-w2 \
-t '$share/workers/connectmq/demo/a1b2/jobs' -v
Agora publique seis jobs a partir de um terceiro terminal:
for i in 1 2 3 4 5 6; do
mosquitto_pub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-pub \
-t "connectmq/demo/a1b2/jobs" -m "job-$i" -q 1
done
Quando rodamos isso no broker.connectmq.com, o worker 1 recebeu job-1, job-3, job-5 e o worker 2 recebeu job-2, job-4, job-6. Cada job foi processado uma única vez, e adicionar um terceiro worker distribui ainda mais a carga sem mexer nos publishers. As aspas simples em volta do topic são importantes no bash, para que o shell não expanda $share.
Usos típicos são serviços de ingestão escalados horizontalmente, processadores de comandos e qualquer consumidor que você roda como várias réplicas de contêiner.
Topic Aliases: Pacotes Menores em Links Restritos
Topics industriais podem ser longos, por exemplo acme/izmir/machining/line1/cnc1/telemetry. Enviar essa string em cada PUBLISH desperdiça banda em links celulares ou de satélite. Com um topic alias, o cliente envia o topic completo uma vez junto com um alias inteiro e, a partir daí, envia só o número do alias. Cada lado anuncia quantos aliases aceita (Topic Alias Maximum) no CONNECT e no CONNACK. A maioria das bibliotecas cliente cuida dos aliases para você depois que eles são ativados.
User Properties: Metadados Sem Mexer no Payload
User properties são pares chave/valor UTF-8 arbitrários anexados a um pacote. Use-as para indicar o tipo de conteúdo, versões de schema, trace IDs ou a versão de firmware do remetente, enquanto o payload continua sendo uma leitura de sensor limpa.
mosquitto_pub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-pub \
-t "connectmq/demo/a1b2/sensors/t1" -m '{"temperature":22.4}' \
-D publish user-property schema v2 -D publish user-property fw 1.4.0
Um subscriber pode imprimi-las com mosquitto_sub -V mqttv5 -F "%t %p %P".
Request/Response com Response Topic e Correlation Data
Muitos fluxos de IoT são, na verdade, chamadas RPC: "leia sua configuração", "reinicie", "me passe os últimos 10 valores". O MQTT 5 padroniza isso:
- O solicitante assina seu próprio topic de resposta.
- Ele publica a requisição com uma propriedade
Response Topicapontando para esse topic de resposta eCorrelation Dataque identifica a requisição. - O respondente responde no response topic e devolve a correlation data.
Como o response topic é repassado aos subscribers, o respondente não precisa de nenhum conhecimento de roteamento fixo no código. Você pode ver as propriedades chegando com:
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-s \
-t "connectmq/demo/a1b2/#" -F "%t %p | response=%R props=%P"
Controle de Fluxo e Limites Anunciados pelo Servidor
Receive Maximum
O Receive Maximum limita quantas mensagens QoS 1 e QoS 2 podem estar em trânsito (enviadas, mas ainda não confirmadas) ao mesmo tempo. O cliente informa seu limite ao servidor no CONNECT, e o servidor informa o dele ao cliente no CONNACK. Um microcontrolador pequeno pode definir um valor baixo para nunca ser inundado, e o broker pode se proteger de um cliente que publica mais rápido do que consegue confirmar. Para saber mais sobre confirmações, veja Níveis de QoS MQTT Explicados.
Limites no CONNACK
No 3.1.1, o cliente descobria os limites falhando. No MQTT 5, o servidor os anuncia nas propriedades do CONNACK, incluindo Maximum QoS, Retain Available, Wildcard Subscription Available, Shared Subscription Available, Receive Maximum e Topic Alias Maximum. Um cliente bem escrito lê esses valores uma vez e se adapta, por exemplo, caindo para QoS 1 se o QoS 2 não for oferecido no plano atual.
MQTT 5 em Python com Paho 2.x
O script a seguir se conecta com MQTT 5, imprime os limites anunciados no CONNACK e executa um ciclo completo de request/response usando message expiry, user properties, response topic e correlation data.
import time
import uuid
import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes
from paho.mqtt.properties import Properties
BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/a1b2" # use seu próprio ID aleatório
REQ_TOPIC = f"{PREFIX}/rpc/request"
RESP_TOPIC = f"{PREFIX}/rpc/response"
def on_connect(client, userdata, flags, reason_code, properties):
print("CONNACK:", reason_code)
for name in ("MaximumQoS", "RetainAvailable", "ReceiveMaximum",
"TopicAliasMaximum", "SharedSubscriptionAvailable"):
if hasattr(properties, name):
print(f" {name} = {getattr(properties, name)}")
client.subscribe(REQ_TOPIC, qos=1)
client.subscribe(RESP_TOPIC, qos=1)
def on_message(client, userdata, msg):
props = msg.properties
if msg.topic == REQ_TOPIC:
# Lado do respondente: responde no topic solicitado e devolve a correlation data
reply = Properties(PacketTypes.PUBLISH)
reply.CorrelationData = props.CorrelationData
client.publish(props.ResponseTopic, b'{"uptime": 3600}', qos=1,
properties=reply)
elif msg.topic == RESP_TOPIC:
print("Response:", msg.payload.decode(),
"correlation:", props.CorrelationData.decode())
connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 600 # mantém a sessão por 10 minutos
connect_props.ReceiveMaximum = 10 # no máximo 10 mensagens recebidas sem confirmação
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id="demo-a1b2-py", protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, 1883, clean_start=True, properties=connect_props)
client.loop_start()
time.sleep(2)
request = Properties(PacketTypes.PUBLISH)
request.ResponseTopic = RESP_TOPIC
request.CorrelationData = uuid.uuid4().hex.encode()
request.MessageExpiryInterval = 30
request.UserProperty = [("schema", "v1"), ("app", "blog-demo")]
client.publish(REQ_TOPIC, b'{"cmd": "status"}', qos=1, properties=request)
time.sleep(3)
client.loop_stop()
client.disconnect()
Em um sistema real, o solicitante e o respondente são clientes diferentes, mas o código continua o mesmo. Em produção, conecte-se ao seu próprio broker com YOUR_USERNAME, YOUR_PASSWORD e YOUR_CLIENT_ID do portal, de preferência via TLS na porta 8883 (veja boas práticas de segurança MQTT).
Suporte ao MQTT 5 no ConnectMQ
Os brokers ConnectMQ falam MQTT 3.1.1 e MQTT 5.0 sobre TCP, TLS e WebSocket, então dispositivos antigos e novos podem compartilhar o mesmo broker. Os recursos do MQTT 5 implementados atualmente são:
| Recurso | Suporte no ConnectMQ |
|---|---|
| Reason codes | Sim, por exemplo 0x97 Quota exceeded e 0x89 Server busy |
| Session expiry | Sim, com teto por plano (30 minutos no servidor MQTT público) |
| Message expiry interval | Sim |
| Shared subscriptions | Sim, $share/{group}/{filter}; no servidor MQTT público e no plano Serverless (Paid) ou superior |
| Topic alias | Sim |
| Response topic (request/response) | Sim, repassado aos subscribers |
| Limites no CONNACK | Maximum QoS, Retain Available, Wildcard e Shared Subscription Available, Receive Maximum |
| Retained messages | Sim |
A extensão do ConnectMQ para VS Code mostra diretamente os reason codes de CONNACK, SUBACK e PUBACK, o que ajuda muito quando você está investigando por que uma assinatura foi recusada.
Comece com o ConnectMQ
Você pode testar todos os exemplos deste artigo no servidor MQTT público broker.connectmq.com sem conta, usando apenas dados de teste. Quando estiver pronto para ter seu próprio broker isolado com credenciais, cadastre-se em app.connectmq.com: o plano Serverless é gratuito, não exige cartão de crédito e entrega um broker em minutos. Compare as opções em o que é um broker MQTT gerenciado.
Perguntas frequentes
O MQTT 5 é retrocompatível com o MQTT 3.1.1?
O formato na rede é diferente, então o cliente escolhe uma versão ao se conectar. Um broker que suporta as duas, como o ConnectMQ, permite que clientes MQTT 3.1.1 e MQTT 5 troquem mensagens nos mesmos topics.
Preciso do MQTT 5 para usar shared subscriptions?
As shared subscriptions são definidas no padrão MQTT 5. Conecte-se com MQTT 5 (por exemplo, -V mqttv5 nas ferramentas do Mosquitto) e assine $share/{group}/{filter} para obter entrega com balanceamento de carga.
Qual a diferença entre session expiry e message expiry?
O session expiry controla por quanto tempo o broker mantém a sessão e as mensagens enfileiradas de um cliente desconectado. O message expiry controla por quanto tempo uma mensagem individual continua válida antes que o broker a descarte.
Qual recurso do MQTT 5 devo adotar primeiro?
Comece pelos reason codes, porque eles tornam as falhas visíveis sem custo nenhum. Depois, adicione session expiry para dispositivos que dormem e shared subscriptions para serviços de backend que precisam escalar.



