O MQTT normalmente roda sobre uma conexão TCP pura na porta 1883 (ou 8883 com TLS). Os navegadores não conseguem abrir sockets TCP puros, então um app web não pode falar MQTT dessa forma. A solução é o MQTT sobre WebSockets: os mesmos pacotes MQTT, transportados dentro de uma conexão WebSocket que todo navegador suporta. Este guia explica como isso funciona e como evitar os erros que mais pegam as pessoas.
Por que os navegadores precisam de WebSockets
Por motivos de segurança, o JavaScript em uma página web só pode fazer conexões de rede pelas APIs do navegador — fetch, XMLHttpRequest, WebSocket, WebRTC e WebTransport. Nenhuma delas consegue abrir uma conexão TCP arbitrária na porta 1883. Os WebSockets são o encaixe natural para o MQTT porque oferecem um canal duradouro, bidirecional e binário — exatamente o que o MQTT precisa.
Usar WebSockets não serve só para navegadores. Também ajuda quando:
- um firewall ou proxy corporativo só permite tráfego web nas portas 80 e 443;
- você quer que o MQTT compartilhe um load balancer ou reverse proxy com seus serviços HTTP;
- você está criando um dashboard, ferramenta administrativa ou app web mobile que mostra dados de dispositivos ao vivo.
Como funciona o MQTT sobre WebSockets
- O cliente abre uma conexão HTTP(S) e envia uma solicitação de upgrade para WebSocket a uma URL como
wss://broker.emqx.io:8084/mqtt, pedindo o subprotocolomqtt. - O broker responde
101 Switching Protocolse a conexão passa a ser um WebSocket. - A partir daí, os pacotes MQTT (
CONNECT,PUBLISH, …) trafegam dentro de frames WebSocket binários. Tudo acima do transporte — QoS, mensagens retidas, Last Will, propriedades do MQTT 5 — funciona exatamente como sobre TCP.
O broker precisa ter um listener WebSocket habilitado. Esse listener geralmente roda em uma porta diferente da do listener TCP, e alguns brokers esperam um path específico.
Uma consequência prática: os navegadores não deixam o JavaScript definir cabeçalhos personalizados em uma requisição WebSocket, então a autenticação normalmente acontece dentro do próprio MQTT, com os campos de usuário e senha do pacote CONNECT, e não com cabeçalhos HTTP ou cookies.
ws vs wss
ws:// | wss:// | |
|---|---|---|
| Criptografia | Nenhuma — credenciais e payloads em texto puro | TLS, como HTTPS |
| Utilizável em páginas HTTPS | Não (bloqueado como mixed content) | Sim |
| Proxies e firewalls | Às vezes sofrem interferência | Normalmente passa pela porta 443 |
| Uso típico | Apenas desenvolvimento local | Todo o resto |
Como o wss:// usa a pilha TLS do navegador, o certificado do broker precisa ser confiável para o navegador. Um certificado autoassinado falha silenciosamente no JavaScript — abra uma vez a URL https://host:port em uma aba para ver o erro real de certificado.
Mixed content: o erro de navegador mais comum
Se a sua página é servida via https:// (como quase todo site), o navegador bloqueia qualquer tentativa de abrir uma conexão ws://. O console mostra um erro de mixed content ou de segurança, e o cliente MQTT simplesmente nunca se conecta. A solução é sempre a mesma: use o endpoint wss:// do broker. Nosso cliente MQTT online é servido via HTTPS justamente por isso e só se conecta via wss://.
Portas e paths
Não existe uma única porta WebSocket padrão para MQTT; cada broker escolhe a sua. Estes são os endpoints dos brokers públicos do nosso diretório de brokers:
| Broker | ws:// | wss:// | Path |
|---|---|---|---|
| broker.hivemq.com | 8000 | 8884 | /mqtt |
| broker.emqx.io | 8083 | 8084 | /mqtt |
| test.mosquitto.org | 8080 | 8081 | qualquer |
| mqtt.eclipseprojects.io | 80 | 443 | /mqtt |
Um path errado normalmente produz uma falha no handshake (HTTP 404 ou conexão fechada) antes mesmo de o MQTT começar. Uma porta errada geralmente resulta em timeout. Para o panorama completo das portas TCP, TLS e WebSocket, veja portas MQTT explicadas.
Exemplo: MQTT no navegador com MQTT.js
O MQTT.js é o cliente JavaScript mais usado e funciona tanto no Node.js quanto no navegador. No navegador, ele usa WebSockets automaticamente:
import mqtt from 'mqtt';
const client = mqtt.connect('wss://broker.emqx.io:8084/mqtt', {
clientId: `web-${crypto.randomUUID().slice(0, 8)}`,
// username: 'user', password: 'secret', // for private brokers
reconnectPeriod: 2000,
});
client.on('connect', () => {
client.subscribe('testmqtt/ws-demo/#');
client.publish('testmqtt/ws-demo/hello', 'hello from the browser');
});
client.on('message', (topic, payload) => {
console.log(topic, payload.toString());
});
client.on('error', (err) => console.error('MQTT error:', err.message));Habilitando WebSockets no seu próprio broker
Se você roda seu próprio broker, o listener WebSocket costuma ser questão de poucas linhas de configuração. No Mosquitto, por exemplo, você adiciona um segundo listener ao lado do TCP:
listener 1883
protocol mqtt
listener 8080
protocol websocketsPara wss://, você pode configurar os certificados diretamente nesse listener ou, o que é mais comum, terminar o TLS em um reverse proxy na porta 443 e encaminhar o tráfego WebSocket sem criptografia ao broker. O proxy precisa ter o suporte a WebSocket habilitado:
location /mqtt {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 1h;
}Garanta que o read timeout do proxy seja maior que o intervalo de keep-alive do MQTT; caso contrário, o proxy fecha conexões ociosas e os clientes sofrem desconexões sem explicação.
Checklist de solução de problemas
- Usando a porta 1883 ou 8883 no navegador? Essas são portas TCP — mude para o listener WebSocket.
- Página em HTTPS e URL começando com
ws://? Mixed content — usewss://. - O handshake falha imediatamente? Verifique o path (
/mqttou nenhum) e o subprotocolo. - Atrás de um reverse proxy? O nginx e proxies similares precisam encaminhar os cabeçalhos
UpgradeeConnectione permitir conexões de longa duração. - Conecta, mas é derrubado? É um problema no nível do MQTT — veja erros de conexão MQTT.
Testar uma conexão wss:// agora
Perguntas frequentes
Por que meu navegador não consegue se conectar ao MQTT na porta 1883?
Os navegadores não conseguem abrir sockets TCP puros, e a porta 1883 fala MQTT puro sobre TCP. Um cliente no navegador precisa se conectar ao listener WebSocket do broker, usando uma URL ws:// ou wss:// com a porta e o path corretos.
Qual a diferença entre ws e wss no MQTT?
ws:// é uma conexão WebSocket sem criptografia; wss:// é WebSocket sobre TLS. Páginas servidas via HTTPS só podem usar wss://, e wss:// é a única escolha sensata para qualquer coisa além de testes locais.
Qual path devo usar no MQTT sobre WebSockets?
Depende do broker. Muitos brokers, incluindo EMQX e HiveMQ, usam /mqtt. O Mosquitto aceita conexões em qualquer path. Consulte a documentação do broker; um path errado normalmente falha durante o handshake do WebSocket.