O tcpdump é a ferramenta de captura de pacotes que já vem instalada — ou está a um pacote de distância — em quase todo servidor Linux, roteador e gateway. Ele não entende MQTT, mas nem precisa: capturar a conversa TCP na porta 1883 ou 8883 basta para provar quem conectou, quem fechou a conexão e se houve perda de pacotes no caminho. Quando você precisa dos detalhes do MQTT, abre o mesmo arquivo no Wireshark.
Este guia é um conjunto de receitas de tcpdump para MQTT: capturas básicas, filtros BPF que reconhecem tipos de pacote MQTT, capturas em Docker e Kubernetes, buffers rotativos de longa duração e como analisar o que foi capturado.
A captura MQTT básica
# Uma linha por segmento (MQTT sem criptografia e TLS)
sudo tcpdump -i any -nn 'tcp port 1883 or tcp port 8883'
# Gravar em arquivo para o Wireshark
sudo tcpdump -i any -nn -w mqtt.pcap 'tcp port 1883 or tcp port 8883'
# Só o tráfego de um dispositivo
sudo tcpdump -i any -nn 'host 192.168.1.50 and tcp port 1883'As opções que você mais vai usar:
| Opção | Significado |
|---|---|
-i any / -i eth0 | Interface de captura (tcpdump -D lista todas) |
-nn | Não resolver nomes de host nem de porta — mais rápido e sem ambiguidade |
-w file.pcap | Gravar os pacotes em arquivo em vez de imprimir |
-r file.pcap | Ler um arquivo de captura |
-A / -X | Mostrar o payload em ASCII / em hex e ASCII |
-c 200 | Parar após 200 pacotes |
-U | Descarregar cada pacote na hora (necessário ao gravar em um pipe) |
-tttt | Data e hora completas em cada linha |
Para ver algo útil logo de cara, publique em um topic de teste a partir de outro terminal e observe o payload em ASCII:
sudo tcpdump -i any -nn -A 'tcp port 1883' &
mosquitto_pub -h broker.connectmq.com -p 1883 -t 'testmqtt/tcpdump/hello' -m 'hello from tcpdump'Você verá o topic testmqtt/tcpdump/hello e o payload em texto puro dentro do segmento PUBLISH. Na porta 8883 só aparecem bytes criptografados — que é exatamente o objetivo do TLS.
Onde capturar
O ponto de captura define o que você consegue provar. Uma captura no cliente mostra o que o dispositivo realmente enviou e o que voltou, incluindo retransmissões que a aplicação nunca percebe. Uma captura no host do broker mostra o que de fato chegou, depois que NAT, load balancers e proxies fizeram o seu trabalho. Quando as duas não batem, o problema está no meio.
Para um problema persistente, capture dos dois lados ao mesmo tempo com timestamps -tttt e compare. Se o cliente envia um PUBLISH que nunca aparece do lado do broker, investigue o caminho de rede; se o broker recebe e o subscriber nunca recebe, olhe as ACLs, filas e logs do broker.
Lendo a saída do tcpdump
Uma conexão MQTT típica fica assim (endereços encurtados):
10:15:02.114 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [S], seq 1902...
10:15:02.139 IP 203.0.113.10.1883 > 10.0.0.12.52144: Flags [S.], seq 4471..., ack 1902...
10:15:02.139 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [.], ack 1
10:15:02.140 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [P.], length 35 <- CONNECT
10:15:02.166 IP 203.0.113.10.1883 > 10.0.0.12.52144: Flags [P.], length 4 <- CONNACK
10:15:02.167 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [P.], length 42 <- PUBLISH
10:15:02.168 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [P.], length 2 <- DISCONNECT
10:15:02.168 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [F.], ...Os flags TCP carregam a maior parte do diagnóstico:
[S]sem resposta[S.]— o SYN nunca foi respondido: firewall, roteamento ou IP errado. Veja diagnosticar problemas de rede no MQTT.[S]respondido com[R.]— o host está no ar, mas nada escuta na porta (Connection refused).[F.]— um encerramento ordenado. O lado que envia o primeiro FIN é quem decidiu terminar a sessão.[R]— um reset abrupto. Se vier de um endereço que não é nem o cliente nem o broker, um equipamento intermediário derrubou a conexão.- O mesmo segmento
[P.]repetido após um atraso — uma retransmissão, ou seja, perda no caminho.
Filtrar por tipo de pacote MQTT
O primeiro byte de todo pacote MQTT codifica o tipo nos quatro bits superiores. Uma expressão BPF consegue ler esse byte no início do payload TCP, o que permite ao tcpdump manter só certos tipos de pacote:
| Tipo | Primeiro byte (com máscara 0xf0) |
|---|---|
| CONNECT | 0x10 |
| CONNACK | 0x20 |
| PUBLISH | 0x30 |
| SUBSCRIBE | 0x80 |
| PINGREQ / PINGRESP | 0xc0 / 0xd0 |
| DISCONNECT | 0xe0 |
sudo tcpdump -i any -nn -A \
'tcp port 1883 and tcp[tcpflags] & tcp-push != 0 and
((tcp[((tcp[12:1] & 0xf0) >> 2):1] & 0xf0) = 0x10 or
(tcp[((tcp[12:1] & 0xf0) >> 2):1] & 0xf0) = 0x20)'(tcp[12:1] & 0xf0) >> 2 é o tamanho do cabeçalho TCP, então a expressão lê o primeiro byte do payload. A condição tcp-push ignora segmentos ACK vazios. Dois limites: ela só enxerga o primeiro pacote MQTT de cada segmento (vários pacotes pequenos podem dividir um), e os offsets tcp[] funcionam apenas com IPv4. É um filtro para restringir a captura, não um decodificador — para respostas exatas, use o filtro mqtt.msgtype do Wireshark.
Detectar desconexões e reconexões
Dois filtros curtos respondem à pergunta mais comum em produção — "por que este cliente vive desconectando?":
# Cada nova tentativa de conexão (SYN sem ACK)
sudo tcpdump -i any -nn 'tcp port 1883 and tcp[tcpflags] == tcp-syn'
# Cada encerramento ou reset, com timestamps
sudo tcpdump -i any -nn -tttt 'tcp port 1883 and tcp[tcpflags] & (tcp-fin|tcp-rst) != 0'Leia os dois juntos:
- Um FIN do broker cerca de um intervalo e meio de keep-alive depois do último pacote do cliente significa que o cliente parou de enviar PINGREQ — veja keep alive no MQTT.
- Um RST após um longo período ocioso, muitas vezes sempre no mesmo intervalo, aponta para timeout de NAT ou firewall — veja timeout de NAT no MQTT.
- Centenas de SYNs por segundo vindos de muitos dispositivos após uma queda é uma tempestade de reconexões.
- Um FIN do broker logo após um novo SYN de outro endereço com o mesmo client ID indica que a sessão foi assumida por outro cliente. Dê a cada cliente de teste um ID distinto com o gerador de client ID.
Capturas de longa duração
Problemas intermitentes pedem capturas que rodem por horas sem encher o disco. O tcpdump consegue rotacionar os arquivos sozinho:
# 10 arquivos de ~100 MB cada; o mais antigo é sobrescrito
sudo tcpdump -i any -nn -w /var/tmp/mqtt.pcap -C 100 -W 10 'tcp port 1883 or tcp port 8883'
# Um arquivo por hora, com o horário no nome
sudo tcpdump -i any -nn -G 3600 -w '/var/tmp/mqtt-%Y%m%d-%H%M.pcap' 'tcp port 1883'Rode dentro do tmux ou como uma unit temporária do systemd, anote o horário em que o problema acontece e baixe só o arquivo relevante.
Containers, Kubernetes e hosts remotos
Um container de broker normalmente não tem tcpdump. Use emprestado o namespace de rede dele:
docker run --rm --net container:mosquitto nicolaka/netshoot \
tcpdump -i any -nn -U -w - 'tcp port 1883' > broker.pcapkubectl debug -it mosquitto-0 --image=nicolaka/netshoot --target=mosquitto -- \
tcpdump -i any -nn 'tcp port 1883'O container de debug precisa de permissão para capturar (root e a capability NET_RAW); políticas de segurança de pods restritivas podem bloqueá-lo. Mapeamentos de porta e redes bridge têm suas próprias armadilhas, tratadas em problemas de rede do MQTT no Docker.
Para acompanhar um servidor remoto ao vivo no Wireshark, transmita a captura por SSH (o usuário remoto precisa de sudo sem senha para o tcpdump):
ssh admin@gateway.example "sudo tcpdump -i any -nn -U -w - 'tcp port 1883'" | wireshark -k -i -Microcontroladores como o ESP32 não rodam tcpdump. Capture no gateway, no roteador Wi-Fi (o OpenWrt tem pacote de tcpdump) ou em uma porta espelhada do switch, filtrando pelo IP do dispositivo.
Analisando a captura
O tcpdump consegue fazer uma primeira passada em um arquivo salvo:
# Quantas tentativas de conexão, e de onde?
tcpdump -r mqtt.pcap -nn 'tcp[tcpflags] == tcp-syn' | awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn
# Ler payloads em texto puro em torno de um horário
tcpdump -r mqtt.pcap -nn -tttt -A | less
# Passar para o tshark decodificar MQTT
tshark -r mqtt.pcap -Y mqtt -T fields -e frame.time -e ip.src -e mqtt.msgtype -e mqtt.topicPara qualquer coisa além de contar, abra o arquivo no Wireshark: ele decodifica cada pacote MQTT e consegue descriptografar TLS com um key log. O fluxo completo está em depurar MQTT com Wireshark.
Confirme uma correção com uma captura
Uma captura também é o melhor teste de regressão para uma correção de rede. Depois de mudar o keep-alive, um timeout de firewall ou uma configuração de load balancer, rode o filtro de desconexões por mais tempo que o antigo intervalo de falha enquanto um cliente continua conectado — por exemplo, um subscriber no cliente MQTT online em testmqtt/tcpdump/#. Nenhum FIN ou RST nessa janela significa que a correção funciona.
Mantenha um subscriber de teste conectado durante a captura
O tcpdump transforma "a conexão cai às vezes" em timestamps, flags e endereços IP. Capture de forma restrita, deixe os flags dizerem quem fechou a conexão e passe para o Wireshark quando precisar ler os próprios pacotes MQTT.
Perguntas frequentes
Qual é o comando tcpdump para capturar MQTT?
sudo tcpdump -i any -nn -w mqtt.pcap 'tcp port 1883 or tcp port 8883' captura MQTT sem criptografia e com TLS em todas as interfaces, em um arquivo que você pode abrir no Wireshark. Remova -w e adicione -A para ver os payloads de MQTT sem criptografia direto no terminal.
O tcpdump consegue decodificar pacotes MQTT?
Não. O tcpdump mostra segmentos TCP, flags e bytes brutos, mas não tem decodificador MQTT. Capture com tcpdump e depois abra o pcap no Wireshark ou rode tshark -r arquivo.pcap -Y mqtt para ver CONNECT, PUBLISH e os outros pacotes MQTT.
Como rodar tcpdump para um broker dentro do Docker?
Conecte um container de ferramentas ao namespace de rede do broker, por exemplo docker run --rm --net container:mosquitto nicolaka/netshoot tcpdump -i any -nn port 1883. Ele vê exatamente o tráfego do container do broker sem instalar nada nele.



