Logs mostram o que um cliente acha que enviou. Uma captura de pacotes mostra o que realmente passou pelo fio. O Wireshark tem um dissector MQTT completo: ele decodifica os flags do CONNECT, nomes de topic, QoS, packet identifiers, propriedades do MQTT 5 e reason codes, então em segundos você vê se uma mensagem perdida nunca foi publicada, nunca foi confirmada ou nunca foi entregue.
Este guia cobre a captura de tráfego MQTT, os filtros de exibição que você vai usar todo dia, a descriptografia de TLS na porta 8883 e alguns comandos tshark para quando você estiver em um servidor sem interface gráfica.
Capture o tráfego certo
Abra o Wireshark na máquina que roda o cliente (ou o broker, se você o controla) e escolha a interface por onde passa o tráfego: o adaptador Wi-Fi ou Ethernet para brokers remotos, a interface de loopback para um broker em localhost.
Use um filtro de captura para manter o arquivo pequeno. Filtros de captura usam a sintaxe BPF e são definidos antes de iniciar:
tcp port 1883 # MQTT sem criptografia
tcp port 1883 or tcp port 8883 # sem criptografia e TLS
host broker.connectmq.com # tudo de e para o brokerDepois gere o tráfego que deseja analisar — por exemplo, um subscriber e um publisher em um topic exclusivo:
mosquitto_sub -h broker.connectmq.com -p 1883 -t 'testmqtt/wireshark/#' -q 1 -v &
mosquitto_pub -h broker.connectmq.com -p 1883 -t 'testmqtt/wireshark/hello' -q 1 -m 'ping'Se você captura em um servidor, tcpdump -w costuma ser mais prático, e você abre o arquivo no Wireshark depois; veja capturar MQTT com tcpdump.
Os filtros de exibição de que você precisa
Filtros de exibição são aplicados depois da captura e usam os nomes de campo do Wireshark. Os principais campos do dissector MQTT:
| Objetivo | Filtro de exibição |
|---|---|
| Todos os pacotes MQTT | mqtt |
| Só CONNECT / CONNACK | mqtt.msgtype == 1 || mqtt.msgtype == 2 |
| Só PUBLISH | mqtt.msgtype == 3 |
| Um topic ou prefixo de topic | mqtt.topic contains "testmqtt/wireshark" |
| O CONNECT de um cliente | mqtt.clientid == "sensor-01" |
| Conexões recusadas | mqtt.conack.val != 0 |
| Publicações retidas | mqtt.retain == 1 |
| PUBLISH com QoS 1 e 2 | mqtt.msgtype == 3 && mqtt.qos > 0 |
| Tráfego de keep-alive | mqtt.msgtype == 12 || mqtt.msgtype == 13 |
| Conexões resetadas | tcp.flags.reset == 1 |
| Retransmissões TCP | tcp.analysis.retransmission |
Os valores numéricos de mqtt.msgtype são os tipos de pacote de controle do MQTT:
| Valor | Pacote | Valor | Pacote |
|---|---|---|---|
| 1 | CONNECT | 8 | SUBSCRIBE |
| 2 | CONNACK | 9 | SUBACK |
| 3 | PUBLISH | 10 | UNSUBSCRIBE |
| 4 | PUBACK | 11 | UNSUBACK |
| 5 | PUBREC | 12 | PINGREQ |
| 6 | PUBREL | 13 | PINGRESP |
| 7 | PUBCOMP | 14 | DISCONNECT |
O tipo 15 é AUTH (só MQTT 5). Para o layout em bytes por trás desses campos, veja estrutura dos pacotes MQTT.
Lendo um CONNECT e um CONNACK
Selecione um pacote CONNECT e expanda MQ Telemetry Transport Protocol. Você verá:
- Nome e versão do protocolo —
MQTTcom versão 4 (3.1.1) ou 5. Se o broker não aceita a versão, ele responde com um erro de unacceptable protocol version. - Connect flags — clean session / clean start, will flag, will QoS, will retain e se há username e password.
- Keep alive — o intervalo em segundos que o cliente prometeu.
- Client ID e, na porta 1883 sem criptografia, o username e o password em texto puro.
- Propriedades do MQTT 5, como session expiry interval, receive maximum e maximum packet size.
O CONNACK seguinte traz o resultado. No MQTT 3.1.1 é um return code (0 significa aceito); no MQTT 5 é um reason code como 0x86 Bad User Name or Password ou 0x87 Not authorized, às vezes com um reason string. Consulte qualquer valor na ferramenta de reason codes. O detalhamento campo a campo está em o pacote CONNECT do MQTT.
Se não houver CONNACK e o broker mandar um RST ou FIN TCP, ele rejeitou a conexão antes mesmo de chegar ao MQTT — muitas vezes um listener TLS recebendo MQTT sem criptografia, um pacote malformado ou um limite de conexões.
Seguindo uma mensagem de ponta a ponta
Para provar onde uma mensagem se perdeu, siga-a pela captura:
- Filtre
mqtt.topic contains "testmqtt/wireshark"e encontre o PUBLISH do publisher. Anote o Message Identifier se for QoS 1 ou 2. - Filtre
mqtt.msgid == <id>para ver o PUBACK (QoS 1) ou a sequência PUBREC / PUBREL / PUBCOMP (QoS 2). Sem PUBACK, o broker nunca aceitou a mensagem — verifique ACLs e o tamanho do payload. - Se você também capturou do lado do subscriber, procure o PUBLISH que o broker entregou. O packet identifier é diferente, porque cada salto tem o seu.
Statistics → Flow Graph com "Displayed packets" desenha a troca como um diagrama de sequência — a forma mais rápida de achar uma confirmação faltando.
Descriptografando MQTT sobre TLS (porta 8883)
Na porta 8883 você só verá registros TLS até o Wireshark ter as chaves de sessão. A forma padrão de obtê-las é um arquivo de key log, que muitas bibliotecas TLS conseguem gravar.
Python (paho-mqtt 2.x) — defina keylog_filename no contexto SSL:
import ssl
import paho.mqtt.client as mqtt
ctx = ssl.create_default_context()
ctx.keylog_filename = "/tmp/mqtt-tls-keys.log" # Python 3.8+
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.tls_set_context(ctx)
client.connect("broker.connectmq.com", 8883)
client.loop_start()
client.publish("testmqtt/wireshark/tls", "hello over TLS", qos=1).wait_for_publish()
client.loop_stop()
client.disconnect()Node.js (MQTT.js) — use o flag nativo, sem mudar o código:
node --tls-keylog=/tmp/mqtt-tls-keys.log publish.jsNavegadores e curl respeitam a variável de ambiente SSLKEYLOGFILE. Depois, no Wireshark, abra Edit → Preferences → Protocols → TLS e defina (Pre)-Master-Secret log filename com o caminho do key log. Os registros TLS na 8883 viram pacotes MQTT decodificados, tanto em TLS 1.2 quanto em 1.3.
Se o próprio handshake TLS falha, você não precisa descriptografar: o registro de alerta (por exemplo Unknown CA ou Handshake Failure) fica visível. Veja TLS handshake failed.
Portas não padrão e WebSockets
O Wireshark só assume MQTT nas portas registradas. Se seu broker escuta, por exemplo, na 11883, clique com o botão direito em um pacote, escolha Decode As… e associe essa porta TCP ao MQTT.
Para MQTT sobre WebSockets (8083 / 8084), o Wireshark mostra a requisição HTTP de upgrade e os frames WebSocket; os pacotes MQTT ficam dentro de frames binários. Em apps de navegador, costuma ser mais rápido ler esses frames no próprio navegador — veja depurar MQTT no Chrome DevTools.
Receitas de tshark
O tshark é o gêmeo de linha de comando do Wireshark e usa os mesmos filtros:
# Ao vivo: imprime tempo, tipo de pacote, topic e payload
tshark -i any -f "tcp port 1883" -Y mqtt \
-T fields -e frame.time_relative -e mqtt.msgtype -e mqtt.topic -e mqtt.msg
# De um arquivo: conta os PUBLISH por topic
tshark -r mqtt.pcap -Y "mqtt.msgtype == 3" -T fields -e mqtt.topic | sort | uniq -c | sort -rn
# Intervalos entre pings de keep-alive (procure valores próximos ao limite de keep-alive)
tshark -r mqtt.pcap -Y "mqtt.msgtype == 12" -T fields -e frame.time_delta_displayedA última é útil para timeouts de keep-alive: se os intervalos passarem de 1,5 vez o valor de keep-alive, o broker tem o direito de desconectar o cliente.
O que procurar, por sintoma
| Sintoma | O que a captura mostra |
|---|---|
| Cliente "não conecta" | CONNECT seguido de CONNACK com código diferente de zero, ou RST sem CONNACK |
| Mensagens perdidas em QoS 1 | PUBLISH sem PUBACK e, após reconectar, uma duplicata (flag DUP ativo) |
| Desconexões aleatórias | Lacunas nos PINGREQ, retransmissões TCP e depois FIN ou RST de um dos lados |
| Mensagens grandes somem | Um PUBLISH grande seguido do broker fechando a conexão — compare com o maximum packet size e confira tamanhos na calculadora de tamanho de pacote |
| Subscriber não recebe nada | SUBACK com código de falha 0x80 ou um topic filter que não casa |
Para reproduzir um caso rapidamente, rode a captura enquanto publica pelo cliente MQTT online e veja os pacotes chegando em tempo real.
O Wireshark troca suposições por evidências. Capture de forma restrita, filtre por tipo de pacote e topic, descriptografe TLS só quando precisar e guarde uma captura de uma sessão que funciona — comparar uma captura com problema com uma boa costuma ser o diagnóstico mais rápido de todos.
Perguntas frequentes
Qual é o filtro de exibição do Wireshark para MQTT?
Use 'mqtt' para mostrar todos os pacotes MQTT decodificados. Refine com campos como mqtt.msgtype == 3 para PUBLISH, mqtt.topic contains "sensors" para um topic, ou mqtt.clientid == "sensor-01" para o CONNECT de um cliente.
Por que o Wireshark mostra TLS em vez de MQTT na porta 8883?
Os pacotes MQTT estão criptografados. O Wireshark só consegue decodificá-los se você fornecer as chaves de sessão TLS: faça o cliente gravar um arquivo de key log (SSLKEYLOGFILE, keylog_filename no Python, --tls-keylog no Node) e aponte as preferências de TLS do Wireshark para esse arquivo.
Por que meu tráfego MQTT aparece como dados TCP comuns?
O Wireshark decodifica MQTT automaticamente apenas na porta padrão 1883 (e na 8883 após descriptografar). Para qualquer outra porta, clique com o botão direito em um pacote, escolha Decode As e associe a porta TCP ao MQTT.

