Quando aparece um erro de falha no handshake TLS do MQTT, a conexão morre antes mesmo de o MQTT começar, e a maioria das bibliotecas de cliente o informa com uma mensagem pouco útil. Este guia mostra como isolar a causa em minutos com openssl s_client e depois percorre os seis problemas por trás de quase todas as falhas: porta errada, CA ausente, SNI, relógio dessincronizado, versão de TLS incompatível e proxies que interceptam o tráfego. Todos os testes rodam contra broker.connectmq.com, o servidor MQTT público (gratuito) do ConnectMQ, na porta 8883, para que você possa comparar um endpoint que sabidamente funciona com o seu.
O que acontece em um handshake TLS
Antes de enviar o pacote CONNECT do MQTT, seu cliente precisa concluir um handshake TLS com o broker:
- O cliente envia o ClientHello com as versões de TLS suportadas, as cipher suites e o nome do servidor (SNI).
- O broker responde com a versão e a cifra escolhidas, além de sua cadeia de certificados.
- O cliente verifica a cadeia contra raízes confiáveis, checa as datas de validade e confere o hostname.
- Os dois lados derivam as chaves e passam a trocar tráfego criptografado.
Uma falha em qualquer etapa fecha a conexão. Sua biblioteca MQTT então mostra algo como A TLS error occurred (mosquitto), ssl.SSLError (Python), ECONNRESET ou um erro de certificado (Node.js), ou state=-2 (PubSubClient no ESP32). O que você precisa é do motivo subjacente, e o OpenSSL o mostra diretamente. Para as configurações de referência corretas, veja nosso guia de configuração de TLS no MQTT.
Passo 1: reproduza o handshake com openssl s_client
Execute isto na mesma máquina ou rede do cliente com falha:
openssl s_client -connect broker.connectmq.com:8883 \
-servername broker.connectmq.com -showcerts </dev/null
Um resultado saudável termina com linhas parecidas com:
Verify return code: 0 (ok)
e mostra o protocolo e a cifra negociados. Se o OpenSSL tiver sucesso mas sua aplicação falhar, o problema está na configuração da aplicação (caminho da CA, hostname, opções da biblioteca). Se o OpenSSL também falhar, o problema é a rede, o repositório de confiança ou o relógio. Essa única comparação reduz a busca pela metade.
Variações úteis:
# Resumo curto de protocolo, cifra e verificação
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -brief </dev/null
# Verifica contra um arquivo de CA específico, como faria um dispositivo embarcado
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com \
-CAfile isrgrootx1.pem </dev/null
# Inspeciona as datas e os nomes do certificado
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
Falha no handshake TLS do MQTT: sintomas e causas
| Sintoma | Causa provável | Correção |
|---|---|---|
wrong version number ou packet length too long |
Cliente TLS falando com uma porta sem criptografia (1883) | Use a porta 8883 para TLS |
| A conexão trava e depois expira | Cliente MQTT sem TLS na porta 8883, ou porta bloqueada por firewall | Ative o TLS no cliente; teste a acessibilidade |
unable to get local issuer certificate (código 20) |
O cliente não confia na CA raiz | Instale ou aponte para o pacote de CAs correto |
self-signed certificate in certificate chain (código 19) |
Proxy ou antivírus interceptando e substituindo o certificado | Contorne a inspeção ou confie deliberadamente na CA do proxy |
certificate is not yet valid (código 9) |
O relógio do dispositivo está atrasado | Sincronize o horário com NTP antes de conectar |
certificate has expired (código 10) |
O relógio está adiantado, ou o certificado do servidor realmente expirou | Verifique o relógio do dispositivo e as datas do servidor |
Hostname mismatch / IP address mismatch |
Conexão por IP ou pelo nome errado | Conecte-se pelo hostname que consta no certificado |
no protocols available / unsupported protocol |
Cliente limitado a versões de TLS que o servidor não oferece | Permita TLS 1.2 ou mais recente no cliente |
alert handshake failure |
Nenhuma cipher suite em comum ou SNI ausente | Atualize a biblioteca TLS; envie o SNI |
Causa 1: porta ou esquema errado
Este é o erro mais comum. A porta 1883 fala MQTT sem criptografia; a porta 8883 espera TLS desde o primeiro byte. Se o seu cliente iniciar TLS contra a 1883, o OpenSSL informa wrong version number porque a resposta do servidor não é um registro TLS. Se um cliente sem criptografia se conectar à 8883, o broker fica esperando um ClientHello que nunca chega e a conexão acaba sendo fechada.
Verifique também o esquema da URL. No MQTT.js, mqtt:// significa sem criptografia e mqtts:// significa TLS; nos navegadores, use wss://broker.connectmq.com:8084/mqtt. Em Python, é a chamada a tls_set() que ativa o TLS; mudar apenas a porta não basta.
Para verificar se a porta está acessível:
# Linux/macOS
nc -vz broker.connectmq.com 8883
# Windows PowerShell
Test-NetConnection broker.connectmq.com -Port 8883
Redes corporativas e de visitantes costumam bloquear a 8883. Se ela estiver bloqueada, WebSocket seguro na 8084 é uma alternativa comum; veja MQTT sobre WebSocket.
Causa 2: certificado de CA ausente ou errado
O erro de verificação 20 significa que o cliente não conseguiu montar uma cadeia até uma raiz confiável. Situações típicas:
- Os clientes do mosquitto não usam o repositório do sistema, a menos que você informe
--capath /etc/ssl/certs(Linux) ou--cafile. No Windows, baixe o PEM da ISRG Root X1 e informe-o com--cafile. - Imagens Docker mínimas muitas vezes não têm o pacote
ca-certificates. - Dispositivos embarcados receberam a raiz errada, um PEM truncado ou o certificado folha em vez da raiz.
- O Python no macOS instalado a partir do python.org precisa que seu instalador de certificados seja executado uma vez; os detalhes estão em SSL CERTIFICATE_VERIFY_FAILED no MQTT.
O certificado do broker da ConnectMQ é emitido pela Let's Encrypt, então qualquer repositório de confiança de sistema atualizado já inclui a raiz necessária.
Causa 3: SNI ausente
O Server Name Indication informa ao servidor qual hostname você quer. Endpoints com balanceamento de carga e multi-tenant podem apresentar um certificado padrão, ou rejeitar o handshake, quando o SNI está ausente. A maioria das bibliotecas envia o SNI automaticamente quando você se conecta com um hostname. Os problemas surgem quando o código resolve o endereço IP primeiro e se conecta ao IP, ou quando são usadas pilhas TLS muito antigas. Sempre passe o hostname para a biblioteca de cliente e, nos testes com OpenSSL, sempre inclua -servername.
Causa 4: relógio dessincronizado
Certificados só são válidos entre duas datas. Um Raspberry Pi sem horário de rede, um ESP32 que ainda não concluiu o NTP ou uma VM restaurada de um snapshot antigo podem estar dias ou décadas fora. Verifique com date -u no Linux e, em microcontroladores, aguarde o NTP antes de abrir a conexão TLS. O guia de certificate pinning no ESP32 inclui um loop de espera do NTP pronto para usar.
Causa 5: versão de TLS ou cifra incompatível
Firmware antigo, runtimes Java legados ou configurações fixas no código, como o ssl.PROTOCOL_TLSv1 do Python, podem oferecer apenas versões que os servidores modernos desativaram. Teste quais versões um servidor aceita:
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -tls1_2 </dev/null
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -tls1_3 </dev/null
Configure seu cliente para negociar automaticamente (por exemplo, ssl.PROTOCOL_TLS_CLIENT em Python) em vez de fixar uma única versão. Nosso artigo sobre MQTT sobre TLS 1.3 explica com mais profundidade as escolhas de versão e de cifra.
Causa 6: inspeção de TLS e proxies
Alguns firewalls corporativos e produtos antivírus interceptam o TLS apresentando o próprio certificado. O sintoma é o erro de verificação 19 e um nome de emissor pertencente ao produto de segurança. Peça à sua equipe de rede para isentar o hostname do broker ou, se a inspeção for obrigatória, confie explicitamente na CA da organização apenas naquele ambiente. Nunca entregue dispositivos com a verificação desativada para contornar um proxy.
Checklist sistemático
- Execute
openssl s_clientcom-servernamea partir do ambiente com falha. - Confirme que a porta corresponde ao transporte: 1883 sem criptografia, 8883 TLS, 8084 WebSocket seguro.
- Confirme que o cliente se conecta pelo hostname, e não pelo IP.
- Verifique se o repositório de confiança ou o arquivo de CA contém a raiz certa.
- Verifique o relógio do sistema em UTC.
- Permita a negociação automática da versão de TLS.
- Descarte proxies testando a partir de outra rede, como o roteador do celular.
- Só depois que o handshake tiver sucesso, depure erros no nível do MQTT, como credenciais erradas ou conflito de client ID.
O último ponto importa: um handshake bem-sucedido seguido de uma desconexão com um reason code no CONNACK é um problema de autenticação ou de protocolo, e não de TLS.
Menos problemas de handshake com um broker gerenciado
Muitos incidentes de TLS em brokers auto-hospedados vêm do lado do servidor: certificados expirados, cadeias incompletas ou um listener mal configurado após uma atualização. Um broker MQTT gerenciado transfere essa responsabilidade para o provedor. A ConnectMQ oferece TLS na 8883 e WebSocket seguro na 8084 com certificados Let's Encrypt renovados automaticamente, então, se um handshake falhar, você sabe que deve olhar para o lado do cliente. Você pode testar qualquer cliente primeiro contra o servidor MQTT público, reservado a testes e protótipos, e nosso guia de broker MQTT na nuvem mostra como os brokers MQTT gerenciados se encaixam na produção.
Comece a usar a ConnectMQ
Crie um broker gratuito em app.connectmq.com no plano Serverless, sem cartão de crédito, copie as credenciais geradas e use o cliente MQTT no navegador disponível no portal para confirmar que o broker funciona antes de depurar o código do seu próprio dispositivo.
Perguntas frequentes
Por que o mosquitto_sub diz apenas "A TLS error occurred"?
Os clientes do mosquitto escondem o detalhe do OpenSSL. Execute openssl s_client com o mesmo host, porta e arquivo de CA para ver o erro de verificação exato.
Usuário ou senha errados podem causar falha no handshake TLS?
Não. As credenciais são verificadas depois do handshake, dentro da troca CONNECT do MQTT. Um problema de credenciais aparece como uma recusa no CONNACK, e não como um erro de TLS.
Meu cliente funciona no Wi-Fi de casa, mas não no escritório. Por quê?
A rede do escritório provavelmente bloqueia a porta 8883 ou inspeciona o tráfego TLS. Teste com Test-NetConnection ou nc e experimente WebSocket seguro na porta 8084.
Devo desativar a verificação de certificado para conseguir conectar?
Não. Desativar a verificação esconde o problema real e remove a proteção contra brokers impostores. Corrija a CA, o hostname ou o relógio.



