MQTT is the lightweight publish/subscribe protocol behind most IoT and home-automation setups. Devices publish messages to topics (home/livingroom/temperature), and other clients subscribe to the topics they care about. A broker sits in the middle and routes the messages. Eclipse Mosquitto is the most widely used open-source broker: small, fast and easy to run on a VPS, giving your devices a stable, reachable broker anywhere.
Install
sudo apt install mosquitto mosquitto-clients
sudo systemctl enable --now mosquitto
Docker alternative: eclipse-mosquitto:2 with a mounted mosquitto.conf, data and log directories.
Since Mosquitto 2.0, the default config only allows local connections without authentication. You must configure listeners explicitly for remote access, which is safe by default.
Basic configuration with authentication
/etc/mosquitto/conf.d/default.conf:
per_listener_settings false
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
# plain MQTT only on localhost (local apps)
listener 1883 127.0.0.1
# TLS for remote clients
listener 8883
certfile /etc/mosquitto/certs/fullchain.pem
keyfile /etc/mosquitto/certs/privkey.pem
Create users:
sudo mosquitto_passwd -c /etc/mosquitto/passwd sensor1 # -c only for the first user
sudo mosquitto_passwd /etc/mosquitto/passwd nodered
sudo chown mosquitto: /etc/mosquitto/passwd && sudo chmod 640 /etc/mosquitto/passwd
ACLs: who can read and write which topics
/etc/mosquitto/acl:
# sensors may only publish their own data
user sensor1
topic write sensors/sensor1/#
# the automation service reads all sensors and writes commands
user nodered
topic read sensors/#
topic write commands/#
# pattern: each client may use its own subtree (%u = username)
pattern readwrite devices/%u/#
Least privilege matters. A compromised device shouldn’t be able to control everything.
TLS with Let’s Encrypt
Get a certificate for mqtt.example.com (standalone, or via your web server):
sudo certbot certonly --standalone -d mqtt.example.com
sudo mkdir -p /etc/mosquitto/certs
sudo cp /etc/letsencrypt/live/mqtt.example.com/{fullchain,privkey}.pem /etc/mosquitto/certs/
sudo chown mosquitto: /etc/mosquitto/certs/*.pem && sudo chmod 600 /etc/mosquitto/certs/privkey.pem
Mosquitto can’t read Certbot’s root-only files directly. Use a deploy hook to copy the files and reload Mosquitto on renewal:
sudo tee /etc/letsencrypt/renewal-hooks/deploy/mosquitto.sh >/dev/null <<'EOF'
#!/bin/sh
cp /etc/letsencrypt/live/mqtt.example.com/fullchain.pem /etc/letsencrypt/live/mqtt.example.com/privkey.pem /etc/mosquitto/certs/
chown mosquitto: /etc/mosquitto/certs/*.pem
systemctl reload mosquitto
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/mosquitto.sh
See Let’s Encrypt.
Restart and open the firewall:
sudo systemctl restart mosquitto
sudo ufw allow 8883/tcp
Don’t expose unencrypted 1883 to the internet, since credentials would travel in plain text.
Test
# subscribe (terminal 1)
mosquitto_sub -h mqtt.example.com -p 8883 -u nodered -P 'secret' -t 'sensors/#' -v --capath /etc/ssl/certs
# publish (terminal 2)
mosquitto_pub -h mqtt.example.com -p 8883 -u sensor1 -P 'secret' -t 'sensors/sensor1/temp' -m '21.5' --capath /etc/ssl/certs
Check the logs for authentication or ACL denials:
sudo journalctl -u mosquitto -f
WebSockets (for browser dashboards)
listener 9001
protocol websockets
certfile /etc/mosquitto/certs/fullchain.pem
keyfile /etc/mosquitto/certs/privkey.pem
Browser clients (MQTT.js) connect to wss://mqtt.example.com:9001. Alternatively, proxy WebSockets through Nginx on 443. See Nginx WebSocket proxy.
Useful MQTT features
- QoS 0/1/2: delivery guarantees, from fire-and-forget to exactly-once.
- Retained messages: the broker keeps the last value per topic for new subscribers (
-rwith mosquitto_pub). Good for device states. - Last Will: the broker publishes a message when a client disconnects unexpectedly (“device offline”).
- Bridging: connect a local broker (at home) to the VPS broker, so local devices stay local and selected topics sync to the cloud. Configure
connectionblocks in the localmosquitto.conf.
Integrations
- Node-RED for flows and dashboards.
- Home Assistant MQTT integration.
- Telegraf → InfluxDB for time-series storage, then Grafana.
Quick reference
| Task | Command / setting |
|---|---|
| Add user | mosquitto_passwd /etc/mosquitto/passwd USER |
| No anonymous | allow_anonymous false |
| TLS listener | listener 8883 + certfile/keyfile |
| Subscribe | mosquitto_sub -t 'topic/#' -v |
| Publish | mosquitto_pub -t topic -m msg |
| Logs | journalctl -u mosquitto |
Related: time-series databases and UFW firewall.