Testes de brokers

Diagnosticar problemas de rede no MQTT: DNS, firewalls e proxies

Descubra por que seu cliente MQTT não alcança o broker: teste DNS, rotas TCP, firewalls, proxies corporativos e interceptação TLS, camada por camada.

Atualizado · 9 min de leitura

Diagnosticar problemas de rede no MQTT: DNS, firewalls e proxies

Quando um cliente MQTT falha com um vago "connection failed", a causa quase nunca é o MQTT em si. Normalmente é uma das quatro camadas abaixo dele: o DNS não resolveu o nome do broker, o TCP não alcançou a porta, um proxy ou firewall engoliu a conexão em silêncio, ou o TLS foi interceptado e o certificado não confere mais. Testar essas camadas em ordem — DNS → TCP → TLS → MQTT — encontra a camada quebrada em poucos minutos.

Este guia traz o comando exato para cada camada, as mensagens de erro que cada falha produz e um script Python que executa a cadeia inteira e mostra onde ela quebra.

Leia primeiro a mensagem de erro

O texto do erro já indica qual camada olhar. Estas são as mensagens mais pesquisadas:

ErroCamadaCausa comum
getaddrinfo ENOTFOUND broker.connectmq.com (Node.js)DNSHost digitado errado, sem servidor DNS, DNS split-horizon
[Errno -2] Name or service not known (Python, Linux)DNSIgual ao anterior
[Errno 8] nodename nor servname provided, or not known (Python, macOS)DNSIgual ao anterior
getaddrinfo EAI_AGAINDNSResolver inacessível ou com falha temporária
connect ETIMEDOUT / TimeoutError: timed outTCP / firewallPacotes descartados no caminho, IP errado, porta bloqueada
connect ECONNREFUSED / [Errno 111] Connection refusedTCPHost alcançável, nada escutando naquela porta
ECONNRESET logo após conectarProxy / firewallUm equipamento intermediário derrubou a conexão após inspecioná-la
certificate verify failed: unable to get local issuer certificateTLSFalta o bundle de CAs ou há interceptação TLS
self signed certificate in certificate chainTLSProxy corporativo reassinando o tráfego

Se você já recebe um CONNACK com reason code, a rede está ok e o problema é autenticação ou configuração — consulte a referência de reason codes.

Camada 1: resolução DNS

Verifique se o nome resolve, e se resolve para os mesmos endereços em todo lugar:

Resolver o nome do broker
dig +short broker.connectmq.com A
dig +short broker.connectmq.com AAAA

# Compare com um resolver público para detectar split-horizon ou registros antigos
dig +short broker.connectmq.com @1.1.1.1

# Windows
nslookup broker.connectmq.com

O que observar:

  • Sem resposta — o nome não existe nesse resolver. Confira a grafia e se uma VPN ou o DNS corporativo sobrescreve zonas externas.
  • Respostas diferentes entre o seu resolver e um público — DNS split-horizon, registro antigo em cache após uma migração de broker, ou um filtro DNS devolvendo o IP de uma página de bloqueio.
  • Um registro AAAA sem rota IPv6 — o cliente tenta IPv6 primeiro e trava até fazer fallback. Veja problemas de IPv6 no MQTT.

Dentro de containers, o DNS vem do runtime, não do host. Rode o mesmo dig dentro do container (docker exec -it app sh) antes de supor que o resultado do host vale ali.

Camada 2: alcance TCP e roteamento

A resolução funciona; agora abra uma conexão TCP direta em cada porta MQTT que você pode usar:

Testar as portas MQTT
nc -vz -w 5 broker.connectmq.com 1883   # MQTT sobre TCP
nc -vz -w 5 broker.connectmq.com 8883   # MQTT sobre TLS
nc -vz -w 5 broker.connectmq.com 8084   # MQTT sobre WebSockets seguros
Windows PowerShell
Test-NetConnection broker.connectmq.com -Port 8883

A diferença entre um timeout e uma recusa é o sinal mais útil na depuração de rede:

  • succeeded / TcpTestSucceeded : True — o caminho está aberto; siga para o TLS.
  • Connection refused — você chegou ao host, mas nada escuta ali. Porta errada ou broker fora do ar.
  • Trava e depois dá timeout — algo entre você e o broker descarta os pacotes. Quase sempre é um firewall.

Para ver onde os pacotes param, trace a rota na porta real, não com ICMP (que muitas redes tratam de forma diferente):

Traçar o caminho TCP
sudo traceroute -T -p 8883 broker.connectmq.com   # Linux
mtr --tcp --port 8883 broker.connectmq.com        # se o mtr estiver instalado

Se o trace morre no seu próprio gateway ou no primeiro salto corporativo, o bloqueio é local. Se morre longe, o problema está mais adiante ou na borda do broker. Um passo a passo completo está em testar se uma porta MQTT está aberta, e os números de porta padrão estão em portas MQTT.

Camada 3: firewalls e proxies

Redes de escritório, hotel e nuvem muitas vezes só liberam HTTP(S) de saída, através de um proxy explícito. Clientes MQTT não leem HTTP_PROXY por padrão, então a conexão direta simplesmente dá timeout.

Primeiro, descubra se há um proxy configurado:

Procurar configurações de proxy
env | grep -i _proxy
# Windows: netsh winhttp show proxy

Depois verifique se o proxy faz túnel até a porta do broker com um CONNECT HTTP:

Túnel através de um proxy HTTP
nc -X connect -x proxy.example.corp:3128 -vz broker.connectmq.com 8883

Se o proxy recusa CONNECT na 8883 mas libera a 443, você tem duas opções: usar MQTT sobre WebSockets seguros em uma porta que o proxy permita, ou pedir à equipe de rede que libere o host do broker. Clientes no navegador passam automaticamente pelo proxy do sistema, e é por isso que o cliente MQTT online costuma funcionar em redes onde um cliente nativo falha. Mais estratégias em MQTT atrás de um firewall corporativo e MQTT na porta 443.

Camada 4: TLS e interceptação

A porta TCP está aberta, mas o TLS falha. Veja o certificado que o cliente realmente recebe:

Inspecionar a cadeia de certificados
openssl s_client -connect broker.connectmq.com:8883 \
  -servername broker.connectmq.com -showcerts </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

Compare a linha issuer com o que você obtém pelo hotspot do celular ou pela rede de casa. Se no escritório o emissor for o nome da sua empresa ou de um fornecedor de segurança, um proxy com inspeção TLS está reassinando a conexão. Seu cliente MQTT a rejeita com certificate verify failed ou self signed certificate in certificate chain — e esse é o comportamento correto.

Correções, em ordem de preferência:

  1. Peça que o host do broker seja excluído da inspeção TLS (MQTT não é HTTP, e muitos produtos de inspeção o quebram de qualquer forma).
  2. Se a política exige inspeção, adicione a CA raiz corporativa ao trust store do cliente — nunca desative a verificação de certificado.
  3. Garanta que o cliente envia SNI (o -servername acima): sem ele, alguns endpoints devolvem outro certificado, o que gera erros de hostname mismatch.

Se o handshake trava em vez de falhar, principalmente em VPN, desconfie de um problema de MTU: pacotes pequenos passam, mas a mensagem grande do certificado é descartada. Testar com um MTU menor na interface confirma. Erros de TLS em geral estão em MQTT TLS handshake failed.

Rode a cadeia inteira com um script

Este script (Python 3.8+, paho-mqtt 2.x) testa cada camada em ordem, para na primeira falha e imprime o tempo de cada etapa:

netcheck.py
import os, socket, ssl, sys, time
import paho.mqtt.client as mqtt

HOST, PORT = "broker.connectmq.com", 8883

def dns():
    infos = socket.getaddrinfo(HOST, PORT, proto=socket.IPPROTO_TCP)
    return ", ".join(sorted({i[4][0] for i in infos}))

def tcp():
    with socket.create_connection((HOST, PORT), timeout=5) as s:
        return f"connected to {s.getpeername()[0]}"

def tls():
    ctx = ssl.create_default_context()
    with socket.create_connection((HOST, PORT), timeout=5) as raw:
        with ctx.wrap_socket(raw, server_hostname=HOST) as s:
            issuer = dict(x[0] for x in s.getpeercert()["issuer"])
            return f"{s.version()}, issuer: {issuer.get('organizationName')}"

def mqtt_connect():
    result = {}
    c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, protocol=mqtt.MQTTv5)
    c.on_connect = lambda cl, ud, flags, reason, props: result.setdefault("rc", reason)
    if os.getenv("MQTT_USER"):
        c.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASS"))
    c.tls_set()
    c.connect(HOST, PORT, keepalive=30)
    c.loop_start()
    for _ in range(50):
        if "rc" in result:
            break
        time.sleep(0.1)
    c.disconnect()
    c.loop_stop()
    if "rc" not in result:
        raise TimeoutError("no CONNACK within 5 s")
    if result["rc"].is_failure:
        raise RuntimeError(f"CONNACK: {result['rc']}")
    return f"CONNACK: {result['rc']}"

for name, step in [("DNS", dns), ("TCP", tcp), ("TLS", tls), ("MQTT", mqtt_connect)]:
    start = time.perf_counter()
    try:
        info = step()
    except Exception as e:
        print(f"FAIL  {name:<5} {type(e).__name__}: {e}")
        sys.exit(1)
    print(f"OK    {name:<5} {(time.perf_counter() - start) * 1000:6.0f} ms  {info}")

Uma execução saudável imprime quatro linhas OK. Uma falha mostra a camada e a exceção exata, que corresponde diretamente à tabela do início deste artigo. Rode na máquina que tem o problema — um notebook em outra rede não prova nada sobre o dispositivo que falha.

Confirme a correção

Depois de mudar DNS, regras de firewall ou configurações de proxy, verifique de ponta a ponta em vez de confiar na mudança:

  1. Rode netcheck.py de novo na máquina afetada e confirme que as quatro camadas passam.
  2. Assine um topic de teste no cliente online e publique nele a partir do dispositivo afetado.
  3. Deixe a conexão ociosa por mais tempo que o timeout suspeito do firewall e confira se as mensagens continuam chegando.

Abra o cliente online para testar a entrega

Problemas de rede parecem aleatórios até você separá-los em camadas. Resolva o nome, abra o socket, inspecione o certificado e só então fale MQTT — a primeira etapa que falhar é a que precisa de correção, e a mensagem de erro geralmente já diz qual é.

Perguntas frequentes

Por que meu cliente MQTT funciona em casa mas não no escritório?

Redes corporativas costumam bloquear portas de saída como 1883 e 8883, forçar o tráfego por um proxy HTTP ou inspecionar o TLS. Teste cada camada a partir da rede do escritório: DNS, uma conexão TCP direta, o emissor do certificado TLS e depois o MQTT. MQTT sobre WebSockets na porta 443 costuma ser a saída.

Como saber se um firewall está descartando o tráfego MQTT?

Um firewall que descarta pacotes gera um timeout (ETIMEDOUT, 'timed out'), enquanto uma porta fechada em um host alcançável responde na hora com 'Connection refused'. Rode nc -vz ou Test-NetConnection contra a porta e compare com outra porta do mesmo host.

Como detectar interceptação TLS na minha rede?

Rode openssl s_client contra o broker e imprima o emissor do certificado. Se o emissor for a CA da sua empresa ou de um produto de segurança em vez de uma CA pública, a conexão está sendo interceptada e seu cliente vai falhar na verificação do certificado, a menos que confie nessa CA.