MQTT 3.1.1 vs 5.0 é a questão de versão que toda equipe enfrenta quando um projeto cresce além do protótipo: o protocolo mais novo compensa a migração, e dispositivos antigos e novos conseguem coexistir? Este guia compara como as duas versões se comportam na rede e na prática, lista quais bibliotecas client populares suportam MQTT 5 e traz um checklist de migração para atualizar uma frota mista, um grupo de clients por vez.
Um Breve Histórico
O MQTT 3.1.1 se tornou padrão OASIS em 2014 e ainda é a versão mais implantada. É pequeno, estável e suportado por praticamente toda biblioteca client e todo dispositivo. O MQTT 5.0 veio em seguida como padrão OASIS em 2019. Ele manteve o mesmo modelo central, com topics, níveis de QoS, retained messages e Last Will, e adicionou os recursos que grandes implantações vinham construindo à mão: erros mais claros, expiração, controle de fluxo, metadados e balanceamento de carga. Não existiu uma versão 4; o byte de nível de protocolo do 3.1.1 é 4 e o do 5.0 é 5, e é por isso que as bibliotecas muitas vezes chamam o 3.1.1 de "protocol version 4".
A boa notícia para a migração é que um broker pode atender as duas versões ao mesmo tempo. Cada client declara sua versão no pacote CONNECT, e as mensagens fluem entre clients 3.1.1 e 5.0 nos mesmos topics.
MQTT 3.1.1 vs 5.0 Lado a Lado
| Comportamento | MQTT 3.1.1 | MQTT 5.0 |
|---|---|---|
| Relato de erros | Return codes de 0 a 5 no CONNACK; a maioria das outras falhas apenas fecha a conexão | Reason codes em CONNACK, PUBACK, SUBACK, UNSUBACK, DISCONNECT e outros, mais reason strings opcionais |
| Duração da sessão | Flag clean session: para sempre ou nunca | Clean start mais session expiry interval em segundos |
| Duração da mensagem | Mensagens esperam indefinidamente nas sessões | Message expiry interval por mensagem |
| Consumidores com balanceamento de carga | Não padronizado | Shared subscriptions com $share/group/filter |
| Overhead do topic | Topic completo em todo PUBLISH | Topic alias substitui o topic por um inteiro |
| Metadados | Apenas no payload | User properties, content type, payload format indicator |
| Requisição/resposta | Apenas por convenção | Response topic e correlation data |
| Controle de fluxo | Nenhum padronizado | Receive maximum, maximum packet size |
| Desconexão pelo servidor | O servidor fecha o socket em silêncio | O servidor envia DISCONNECT com um reason code |
| Opções de assinatura | Apenas QoS | No local, retain as published, retain handling, subscription identifiers |
| Mensagem de will | Enviada imediatamente na desconexão abrupta | Will delay interval opcional |
| Autenticação | Usuário e senha | Mais autenticação estendida via pacote AUTH |
| Capacidades do servidor | Implícitas | O servidor pode anunciar QoS máximo, disponibilidade de retain, keep alive imposto, client ID atribuído |
As Mudanças Que Mais Importam na Prática
Reason codes. No 3.1.1, se um broker rejeita uma publicação por causa de uma cota ou permissão, muitas vezes o client só vê a conexão cair e precisa adivinhar o motivo. No MQTT 5 o broker pode dizer por quê, por exemplo 0x97 (quota exceeded) ou 0x87 (not authorized). Só isso já encurta drasticamente a depuração. A referência de reason codes do MQTT lista todos eles.
Expiração de sessão e de mensagem. Com o 3.1.1, uma sessão persistente vive até o client voltar, o que pode significar um broker guardando mensagens para dispositivos desativados há meses. O MQTT 5 permite que o client diga "mantenha minha sessão por 10 minutos" e que os publicadores digam "este comando não serve para nada depois de 30 segundos". Veja session expiry interval no MQTT para dicas de ajuste.
Shared subscriptions. Várias instâncias de um serviço de backend podem assinar $share/workers/orders/+/new, e o broker distribui as mensagens entre elas. Antes do MQTT 5, isso exigia extensões específicas do broker ou uma fila separada.
User properties e requisição/resposta. Metadados como uma versão de schema ou um trace ID podem viajar em propriedades em vez de ser embutidos em cada payload, e fluxos de requisição/resposta ganham um response topic e correlation data padronizados.
Para um tour recurso por recurso com exemplos, leia recursos do MQTT 5.
O Que Não Muda
Sintaxe de topics e wildcards, os três níveis de QoS, retained messages, Last Will, keep alive, portas e TLS funcionam da mesma forma. Os payloads continuam sendo bytes opacos. Um assinante 3.1.1 recebe mensagens publicadas por um client 5.0; ele apenas não vê as propriedades do MQTT 5. Essa compatibilidade é o que torna possível uma atualização gradual.
Suporte em Bibliotecas Client
| Plataforma | Biblioteca | Suporte a MQTT 5 |
|---|---|---|
| Python | paho-mqtt 2.x | Sim, passe protocol=mqtt.MQTTv5 |
| Node.js e navegadores | MQTT.js v5 | Sim, defina protocolVersion: 5 (o padrão é 4) |
| Go | Eclipse Paho paho.mqtt.golang |
Não, apenas 3.1.1 |
| Go | Eclipse Paho paho.golang |
Sim, apenas MQTT 5 |
| Java | Eclipse Paho Java (pacote mqttv5), HiveMQ MQTT Client |
Sim |
| .NET | MQTTnet | Sim |
| ESP32 (ESP-IDF) | esp-mqtt | Sim, quando o suporte a MQTT 5 está habilitado na configuração de build |
| Arduino | PubSubClient, AsyncMqttClient | Não, apenas 3.1.1 |
| CLI | mosquitto_pub e mosquitto_sub | Sim, com -V mqttv5 |
As versões das bibliotecas mudam, então confirme na documentação oficial antes de se comprometer. O padrão a observar: bibliotecas de servidor e de gateway geralmente suportam MQTT 5, enquanto muitas bibliotecas populares para microcontroladores ainda são apenas 3.1.1. Esse é o principal motivo pelo qual as frotas acabam mistas.
Usando Recursos do MQTT 5 no Código
Este exemplo em Python se conecta com MQTT 5, pede uma sessão de 10 minutos, publica um comando com expiração de 30 segundos e user properties e imprime os reason codes. Ele roda contra o servidor MQTT público (gratuito), que suporta as duas versões e expiração de sessão de até 30 minutos; use-o apenas para testes, nunca para dados de produção.
import time
import uuid
import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes
from paho.mqtt.properties import Properties
PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:8]}"
def on_connect(client, userdata, flags, reason_code, properties):
print("CONNACK:", reason_code, "| session present:", flags.session_present)
client.subscribe(f"{PREFIX}/cmd/#", qos=1)
def on_subscribe(client, userdata, mid, reason_code_list, properties):
print("SUBACK:", [str(rc) for rc in reason_code_list])
def on_message(client, userdata, msg):
props = msg.properties
user_props = getattr(props, "UserProperty", None)
expiry = getattr(props, "MessageExpiryInterval", None)
print(f"{msg.topic} {msg.payload.decode()} user={user_props} expiry={expiry}")
def on_publish(client, userdata, mid, reason_code, properties):
print("PUBACK:", reason_code)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"v5-demo-{uuid.uuid4().hex[:8]}",
protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_message = on_message
client.on_publish = on_publish
connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 600 # mantém a sessão por 10 minutos
client.connect("broker.connectmq.com", 1883, keepalive=30,
clean_start=False, properties=connect_props)
client.loop_start()
time.sleep(1)
pub_props = Properties(PacketTypes.PUBLISH)
pub_props.MessageExpiryInterval = 30
pub_props.UserProperty = [("schema", "v2"), ("source", "ops-console")]
pub_props.ContentType = "application/json"
client.publish(f"{PREFIX}/cmd/pump7", '{"action":"stop"}', qos=1,
properties=pub_props)
time.sleep(2)
client.loop_stop()
client.disconnect()
Para ver a interoperabilidade, rode um assinante 3.1.1 no mesmo topic em outro terminal. Ele recebe o payload, mas não as propriedades.
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv311 \
-i v311-check-$RANDOM -t "connectmq/demo/+/cmd/#" -v
Checklist de Migração
Use este checklist para passar do 3.1.1 para o 5.0 sem uma virada de chave única.
- Confirme o suporte do broker. Seu broker precisa aceitar as duas versões simultaneamente. O ConnectMQ aceita, então clients antigos e novos podem compartilhar topics durante a transição.
- Faça o inventário de clients por biblioteca. Liste cada tipo de dispositivo, gateway e serviço com sua biblioteca MQTT e versão. Marque quais podem migrar para MQTT 5 hoje.
- Atualize primeiro os serviços de backend. São eles que mais ganham (reason codes, shared subscriptions, controle de fluxo) e os mais fáceis de reimplantar.
- Substitua a lógica de clean session. Mapeie
clean_session=Truepara clean start com session expiry 0, eclean_session=Falsepara clean start false com uma expiração explícita em vez de "para sempre". - Trate os reason codes. Registre reason codes e reason strings em CONNACK, SUBACK, PUBACK e DISCONNECT, e pare de tentar novamente em códigos que não admitem nova tentativa, como "not authorized".
- Ainda não dependa de propriedades para dados críticos. Enquanto houver assinantes 3.1.1, tudo de que eles precisam deve continuar no payload ou no topic.
- Introduza a expiração de forma deliberada. Adicione message expiry primeiro a comandos e alertas sensíveis ao tempo, em que uma entrega atrasada é prejudicial.
- Adote shared subscriptions para consumidores escalados horizontalmente e remova qualquer deduplicação caseira entre instâncias.
- Atualize gateways e dispositivos por último, por grupo (por exemplo, uma planta ou uma usina por vez), acompanhando o estado das conexões e as taxas de erro depois de cada onda.
- Teste o básico de novo. Reconexão, Last Will, estado retido e sessões persistentes devem se comportar como antes; o checklist de testes MQTT cobre cada um deles.
Vale a Pena Atualizar?
Para projetos novos, comece com MQTT 5 onde suas bibliotecas o suportarem. Para frotas existentes, atualize serviços e gateways agora e os dispositivos quando houver oportunidade, por exemplo no próximo ciclo de firmware. Há pouca razão para apressar dispositivos restritos cuja biblioteca é apenas 3.1.1, porque um broker que fala as duas versões elimina a pressão. O tutorial de MQTT cobre os fundamentos comuns se você estiver integrando novos membros à equipe.
Um broker MQTT gerenciado que suporta as duas versões torna a transição tranquila. O ConnectMQ aceita clients MQTT 3.1.1 e 5.0 no mesmo broker e suporta recursos do MQTT 5 como session expiry, message expiry, topic alias, response topic, retained messages e reason codes, com shared subscriptions no plano Serverless pago.
Atualize no ConnectMQ no Seu Ritmo
Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito, conecte um dispositivo 3.1.1 e um serviço MQTT 5 e confirme que eles interoperam antes de planejar o restante da migração.
Perguntas frequentes
O MQTT 3.1.1 e o MQTT 5.0 são compatíveis?
No mesmo broker, sim. Os clients escolhem a versão no momento da conexão, e as mensagens fluem entre versões. Um assinante 3.1.1 simplesmente não recebe as propriedades do MQTT 5.
Qual é o maior benefício do MQTT 5?
Para a maioria das equipes, são os reason codes, porque as falhas deixam de ser desconexões silenciosas. Expiração de sessão e de mensagem e shared subscriptions vêm logo atrás.
Por que o MQTT 3.1.1 é chamado de protocol version 4?
O pacote CONNECT carrega um byte de nível de protocolo, que é 4 no MQTT 3.1.1 e 5 no MQTT 5.0. Bibliotecas como o MQTT.js usam esse número em suas opções.
Preciso atualizar meus dispositivos ESP32 para MQTT 5?
Não necessariamente. Se você usa uma biblioteca 3.1.1 como a PubSubClient, os dispositivos podem continuar funcionando com um broker que suporta as duas versões enquanto o seu backend adota o MQTT 5.



