How to Set Up an MQTT Broker with Mosquitto (The Messaging Backbone for Home Automation)

Half the smart-home world talks MQTT: a tiny protocol where devices publish messages to named topics ("home/kitchen/temperature: 21.4") and anything interested subscribes. Home Assistant, Frigate, Zigbee2MQTT, Tasmota and ESPHome devices, and any ESP32 you program yourself all use it. They need a broker in the middle, and Mosquitto is the one everybody runs. It's a few megabytes.
Quick reference
| Task | What |
|---|---|
| Folder | ~/docker/mosquitto/compose.yaml + config/mosquitto.conf |
| Port | 1883 (plain, LAN only); 8883 for TLS |
| Users | mosquitto_passwd -c /mosquitto/config/passwd john |
| Test | mosquitto_sub -t 'test/#' -v and mosquitto_pub -t test/hello -m hi |
| Home Assistant | Settings → Devices → Add → MQTT → broker address, user, password |
| See everything | subscribe to # |
1. The compose file
mkdir -p ~/docker/mosquitto/{config,data,log} && cd ~/docker/mosquitto
nano compose.yaml
services:
mosquitto:
image: eclipse-mosquitto:2
container_name: mosquitto
ports:
- "1883:1883"
volumes:
- ./config:/mosquitto/config
- ./data:/mosquitto/data
- ./log:/mosquitto/log
restart: unless-stopped
nano config/mosquitto.conf
listener 1883
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
log_dest stdout
allow_anonymous false
password_file /mosquitto/config/passwd
2. Users
docker compose up -d
docker compose exec mosquitto mosquitto_passwd -c /mosquitto/config/passwd homeassistant
docker compose exec mosquitto mosquitto_passwd /mosquitto/config/passwd frigate
docker compose exec mosquitto mosquitto_passwd /mosquitto/config/passwd sensors
docker compose restart mosquitto
sudo ufw allow from 192.168.1.0/24 to any port 1883
-c creates the file (first user only). One user per client type keeps things tidy and lets you change one password without touching everything.
3. Test it
sudo apt install mosquitto-clients -y
mosquitto_sub -h 192.168.1.50 -u sensors -P password -t 'test/#' -v
In another window:
mosquitto_pub -h 192.168.1.50 -u sensors -P password -t test/hello -m "it works"
The first window prints test/hello it works. That's the whole protocol. -t '#' subscribes to everything — leave it running while setting things up and you'll see every device talking.
4. Connect the apps
- Home Assistant: Settings → Devices & services → Add integration → MQTT → broker 192.168.1.50, port 1883, user homeassistant. Devices that support MQTT discovery (Zigbee2MQTT, Tasmota, Frigate) then appear by themselves.
- Frigate: mqtt: enabled: true, host: 192.168.1.50, user: frigate, password: ... (tutorial 91).
- Zigbee2MQTT: mqtt: server: mqtt://192.168.1.50:1883 in its config, plus user and password.
- Tasmota / ESPHome devices: the MQTT page in their web UI — host, user, password.
5. The three things to know
- Retained messages (-r): the broker keeps the last value so a new subscriber gets it immediately. Use for states (door open/closed), not for events (doorbell pressed).
- QoS: 0 fire-and-forget, 1 at least once, 2 exactly once. Sensors: 0. Commands that must arrive: 1.
- Topics are just slashes: home/kitchen/temperature. + matches one level, # matches everything below. Pick a scheme and stick to it.
6. From the internet
Don't expose 1883. Devices outside the house go through the VPN. If you must, add a TLS listener on 8883 with a Let's Encrypt certificate mounted in, and keep allow_anonymous false.
Troubleshooting
"Connection refused: not authorised". Wrong user/password, or you edited passwd without restarting.
Home Assistant discovers nothing. The device isn't publishing discovery messages, or it's on a different broker address. mosquitto_sub -t 'homeassistant/#' -v shows what's being announced.
Messages arrive late or out of order. QoS 0 over a weak Wi-Fi link. Use QoS 1 for things that matter.
Log file growing. Drop log_dest file; stdout goes to Docker's capped logs (tutorial 67).
Wrapping up
One container, one config file with anonymous access off, a user per client. Then every sensor, camera, bulb and automation in the house has a shared language — and mosquitto_sub -t '#' is the most satisfying debugging tool you'll own.
