Para testar MQTT sobre WebSockets, verifique a conexão em duas etapas: primeiro o upgrade HTTP (URL certa, caminho certo, subprotocolo mqtt, 101 Switching Protocols), depois uma sessão MQTT real dentro do socket (CONNECT, CONNACK, publish, subscribe). A maioria dos problemas com WebSockets — 404, sockets fechados, bloqueios de conteúdo misto — acontece na primeira etapa, antes mesmo de o MQTT entrar em cena.
Os exemplos usam broker.connectmq.com: ws:// na porta 8083 e wss:// na porta 8084, ambos com o caminho /mqtt.
Como é uma conexão MQTT WebSocket funcionando
Uma URL MQTT WebSocket tem quatro partes, e qualquer uma pode estar errada:
| Parte | Exemplo | Erro típico |
|---|---|---|
| Esquema | wss:// | ws:// a partir de uma página HTTPS (bloqueado como conteúdo misto) |
| Host | broker.connectmq.com | Endereço IP com wss — certificado não confere |
| Porta | 8084 | Usar a porta TCP 1883 ou a porta TLS 8883 |
| Caminho | /mqtt | Caminho ausente ou errado — 404 Not Found |
O cliente também envia o cabeçalho Sec-WebSocket-Protocol: mqtt. O broker precisa responder com HTTP/1.1 101 Switching Protocols e devolver Sec-WebSocket-Protocol: mqtt. Depois disso, o socket transporta pacotes MQTT binários comuns — o mesmo CONNECT e CONNACK do TCP. Para o contexto, veja MQTT sobre WebSockets.
Etapa 1: teste o handshake
Com curl
O curl consegue enviar a requisição de upgrade manualmente e mostrar a resposta bruta. Isso isola a parte HTTP de qualquer biblioteca MQTT:
curl -i --http1.1 --max-time 5 \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
-H "Sec-WebSocket-Protocol: mqtt" \
https://broker.connectmq.com:8084/mqttUse http://...:8083/mqtt para testar o listener sem criptografia. Um endpoint saudável responde:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: mqttDepois o curl espera até o --max-time, porque o socket continua aberto — isso é esperado. Outras respostas dizem o que corrigir:
| Resposta | Significado |
|---|---|
101 sem Sec-WebSocket-Protocol: mqtt | O broker ou proxy descarta o subprotocolo; os navegadores vão fechar o socket |
404 Not Found | Caminho errado — tente /mqtt, / ou o caminho documentado do seu broker (detalhes) |
400 Bad Request / 426 Upgrade Required | Cabeçalhos de upgrade ausentes — muitas vezes um proxy que não os repassa |
502 Bad Gateway | O proxy reverso não alcança o listener WebSocket do broker |
Empty reply from server ou reset | A porta é MQTT/TLS comum, não WebSocket |
| Erro de certificado SSL | Os mesmos problemas de TLS da 8883 — o certificado precisa bater com o hostname |
Se o broker estiver atrás do Nginx ou de outro proxy, um 400 ou um subprotocolo ausente quase sempre significam que os cabeçalhos Upgrade e Connection não estão sendo repassados — veja MQTT atrás de um proxy Nginx.
Com wscat
O wscat é um pequeno cliente WebSocket que negocia o subprotocolo corretamente:
npx wscat -c wss://broker.connectmq.com:8084/mqtt -s mqttConnected (press CTRL+C to quit) significa que o handshake e o subprotocolo estão corretos. Alguns segundos depois o broker fecha o socket, porque nenhum pacote MQTT CONNECT chegou — isso é normal e, na verdade, confirma que há um broker MQTT escutando. Sem -s mqtt, muitos brokers recusam o upgrade, o que serve como teste negativo.
Etapa 2: teste uma sessão MQTT real
Os clientes de linha de comando do mosquitto não conectam via WebSockets, então use um cliente compatível. O mais rápido é o cliente MQTT online: informe a URL wss://, conecte, assine um tópico de teste e publique nele. Se funcionar, o lado do broker está correto e qualquer problema restante está na sua aplicação.
Para uma verificação automatizada, este script com MQTT.js 5 roda no Node.js ou, quase sem mudanças, no navegador:
import mqtt from "mqtt";
const url = "wss://broker.connectmq.com:8084/mqtt";
const topic = `testmqtt/ws/${Math.random().toString(16).slice(2, 10)}`;
const client = mqtt.connect(url, {
protocolVersion: 5,
username: process.env.MQTT_USER,
password: process.env.MQTT_PASS,
connectTimeout: 5000,
reconnectPeriod: 0, // falhar rápido durante o teste
});
const started = Date.now();
client.on("connect", (connack) => {
console.log(`CONNACK reason ${connack.reasonCode ?? 0} after ${Date.now() - started} ms`);
client.subscribe(topic, { qos: 1 }, () => client.publish(topic, "ping over websocket", { qos: 1 }));
});
client.on("message", (t, payload) => {
console.log(`round trip ok on ${t}: ${payload}`);
client.end();
});
client.on("error", (err) => { console.error("error:", err.message); process.exit(1); });
client.on("close", () => console.log("socket closed"));O MQTT.js define o subprotocolo mqtt automaticamente. Python também funciona — paho-mqtt 2.x com transport="websockets":
import os
import paho.mqtt.client as mqtt
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, transport="websockets", protocol=mqtt.MQTTv5)
c.ws_set_options(path="/mqtt")
c.tls_set() # remova para ws:// na porta 8083
c.username_pw_set(os.environ["MQTT_USER"], os.environ["MQTT_PASS"])
c.on_connect = lambda cl, u, f, rc, p: print("CONNACK:", rc)
c.connect("broker.connectmq.com", 8084)
c.loop_forever()O caminho WebSocket padrão do paho já é /mqtt, então ws_set_options é opcional aqui — mas brokers que usam / ou um caminho próprio respondem com 404 até você defini-lo explicitamente.
Depurando no DevTools do navegador
Quando uma aplicação web não consegue conectar, o navegador mostra todos os detalhes do handshake:
- Abra o DevTools → Network, filtre por WS (Chrome) ou escolha WS no filtro de tipo (Firefox) e recarregue a página.
- Clique na requisição do socket. Em Headers, confira o status (
101), a URL e o caminho, e se tanto a requisição quanto a resposta incluemSec-WebSocket-Protocol: mqtt. - Abra a aba Messages (Chrome) ou Response (Firefox). O primeiro frame enviado é o CONNECT MQTT binário; o primeiro recebido é o CONNACK. Se o CONNECT sai e o socket fecha sem CONNACK, o broker rejeitou a sessão MQTT (credenciais, client ID), e não o WebSocket.
- Procure no Console erros como estes:
WebSocket connection to 'wss://broker.example.com:8084/mqtt' failed:
Mixed Content: The page at 'https://app.example.com/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://broker.example.com:8083/mqtt'. This request has been blocked; this endpoint must be available over WSS.O primeiro, sem nada depois dos dois-pontos, é a falha genérica do navegador — geralmente porta, caminho ou certificado errados; confira a aba Network. O segundo só se resolve trocando para wss:// (conteúdo misto). Um código de fechamento 1006 significa que a conexão caiu sem um frame de fechamento adequado, muitas vezes por timeout do proxy ou porque o broker recusou a conexão. Para a lista completa de causas, veja MQTT WebSocket connection failed.
Checklist de testes WebSocket
- O curl na URL
wss://retorna101e devolveSec-WebSocket-Protocol: mqtt. - O wscat com
-s mqttconecta; sem ele, o broker recusa ou fecha. - Um cliente real recebe um CONNACK e completa um ciclo de publish/subscribe.
- O navegador conecta a partir de uma página HTTPS com
wss://, sem erros no console. - Através do seu proxy ou load balancer, conexões ociosas sobrevivem por mais tempo que o intervalo de keep-alive.
- Credenciais e ACLs se comportam da mesma forma no listener WebSocket e no TCP.
Teste o endpoint WebSocket no seu navegador
Problemas de WebSocket só parecem misteriosos até você dividi-los em dois. Prove o upgrade HTTP com curl ou wscat, depois a sessão MQTT com um cliente real, e em minutos você saberá se precisa corrigir a URL, o proxy ou as credenciais MQTT.
Perguntas frequentes
Qual é o caminho WebSocket do MQTT?
Não existe um padrão único. /mqtt é o mais comum (EMQX, HiveMQ e ConnectMQ usam, e proxies na frente do Mosquitto costumam roteá-lo), mas alguns brokers escutam em / ou num caminho próprio. Um caminho errado normalmente retorna HTTP 404 durante o handshake.
Qual subprotocolo WebSocket o MQTT usa?
mqtt, tanto no MQTT 3.1.1 quanto no MQTT 5. Clientes antigos de MQTT 3.1 usavam mqttv3.1. O cliente envia o valor em Sec-WebSocket-Protocol e o broker precisa devolvê-lo na resposta 101; se não devolver, os navegadores derrubam a conexão.
O mosquitto_pub consegue conectar via WebSockets?
Não. Os clientes de linha de comando do mosquitto só falam MQTT sobre TCP e TLS. Para testar um listener WebSocket, use um cliente no navegador, MQTT.js, paho-mqtt com transport="websockets" ou um cliente desktop como o MQTTX.


