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

Mosquitto: the MQTT broker — The shared language of the smart home.

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

TaskWhat
Folder~/docker/mosquitto/compose.yaml + config/mosquitto.conf
Port1883 (plain, LAN only); 8883 for TLS
Usersmosquitto_passwd -c /mosquitto/config/passwd john
Testmosquitto_sub -t 'test/#' -v and mosquitto_pub -t test/hello -m hi
Home AssistantSettings → Devices → Add → MQTT → broker address, user, password
See everythingsubscribe 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

5. The three things to know

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.

Call us