Docker is the quickest way to get a disposable, reproducible MQTT broker. The official eclipse-mosquitto image is small and well maintained, but its defaults surprise almost everyone the first time: without a config file, you cannot connect from outside the container. This guide sets up Mosquitto in Docker properly — with persistent volumes, TCP and WebSocket ports and password authentication.
1. Create the folder layout
The image expects three directories under /mosquitto. Mirror them on the host:
mkdir -p mosquitto/config mosquitto/data mosquitto/log
touch mosquitto/config/mosquitto.conf| Host folder | Container path | Purpose |
|---|---|---|
./mosquitto/config | /mosquitto/config | mosquitto.conf, password file, ACL file, certificates |
./mosquitto/data | /mosquitto/data | Persistence database (retained messages, sessions) |
./mosquitto/log | /mosquitto/log | Log files, if you log to a file |
2. Write a minimal mosquitto.conf
Mosquitto 2.x only listens on localhost when no listener is configured — inside a container that means nobody can reach it. This config opens MQTT on 1883 and WebSockets on 9001:
# MQTT over TCP
listener 1883
# MQTT over WebSockets
listener 9001
protocol websockets
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
log_dest stdout
# For a first test only — switched to a password file in step 5
allow_anonymous trueWant TLS, ACLs or bridge settings? The mosquitto.conf generator builds a valid file from a form, and the install guide explains the local-only mode in more detail.
3. Start it with docker run
docker run -d --name mosquitto \
--restart unless-stopped \
-p 1883:1883 -p 9001:9001 \
-v "$PWD/mosquitto/config:/mosquitto/config" \
-v "$PWD/mosquitto/data:/mosquitto/data" \
-v "$PWD/mosquitto/log:/mosquitto/log" \
eclipse-mosquitto:2Pinning the major version tag (eclipse-mosquitto:2) avoids surprise upgrades. Check the logs with docker logs -f mosquitto; you should see Opening ipv4 listen socket on port 1883 and a websockets line for 9001.
4. Or use Docker Compose
For anything beyond a quick test, a Compose file is easier to keep in version control:
services:
mosquitto:
image: eclipse-mosquitto:2
container_name: mosquitto
restart: unless-stopped
ports:
- "1883:1883" # MQTT
- "9001:9001" # MQTT over WebSockets
volumes:
- ./mosquitto/config:/mosquitto/config
- ./mosquitto/data:/mosquitto/data
- ./mosquitto/log:/mosquitto/logdocker compose up -d
docker compose logs -f mosquittoOther services in the same Compose project (Node-RED, Home Assistant, your app) reach the broker by service name: mqtt://mosquitto:1883. Only publish ports to the host that something outside Docker actually needs.
5. Add a password file via docker exec
Anonymous access is fine for a minute of testing, never for anything longer. Create a user with mosquitto_passwd, which ships inside the image:
# -c creates the file (overwrites it if it exists!) — use only for the first user
docker exec -it mosquitto mosquitto_passwd -c /mosquitto/config/passwd alice
# add more users without -c
docker exec -it mosquitto mosquitto_passwd /mosquitto/config/passwd bobThen switch the config from anonymous to password authentication:
allow_anonymous false
password_file /mosquitto/config/passwddocker restart mosquittoACLs and TLS work the same way — the files go in the config volume. See securing Mosquitto with passwords, ACLs and TLS.
6. Test the container
From the host (with the Mosquitto clients installed):
mosquitto_sub -h localhost -p 1883 -u alice -P 'secret' -t 'demo/#' -v &
mosquitto_pub -h localhost -p 1883 -u alice -P 'secret' -t 'demo/hello' -m 'hi from docker'No clients on the host? Use the ones inside the container:
docker exec -it mosquitto mosquitto_sub -h localhost -u alice -P 'secret' -t 'demo/#' -vThe WebSocket listener on 9001 is what browser clients use (ws://<host>:9001). Keep in mind that a page loaded over HTTPS may only open wss:// connections, so testing a local broker from a hosted web client usually needs TLS in front of port 9001 — more in MQTT over WebSockets. To see what a working round trip looks like in the browser, try a public broker first:
Try it in the online MQTT client
Troubleshooting the container
| Symptom | Cause | Fix |
|---|---|---|
| Log says "Starting in local only mode" | The config was not mounted, or it defines no listener | Check the volume path and that mosquitto.conf contains listener 1883 |
| Connection refused from the host | Port not published | Add -p 1883:1883 (or the ports: entry) and recreate the container |
| "not authorised" / CONNACK 5 | Anonymous access disabled, wrong user or password | Recreate the user with mosquitto_passwd, then docker restart mosquitto |
| "Unable to open log file" or persistence errors | The broker user cannot write to the mounted folder | Give UID 1883 write access to ./mosquitto/data and ./mosquitto/log |
| Container restarts in a loop | Invalid directive in the config | Read the last lines of docker logs mosquitto; the bad line is named there |
For CONNACK codes beyond these, the MQTT reason codes reference and the connection errors guide explain what the broker is telling you.
Updating the image
Because config, data and logs live on the host, upgrading is just pulling a newer image and recreating the container. Retained messages and persistent sessions survive as long as the data volume is kept:
docker compose pull mosquitto
docker compose up -d mosquitto
docker compose logs --tail 20 mosquittoWith plain docker run, pull the image, then docker rm -f mosquitto and run the same docker run command again. Keeping that command in a small shell script (or switching to Compose) saves you from retyping the volume flags.
Production tips
- Pin an exact image tag and upgrade deliberately; read the Mosquitto changelog before major upgrades.
- Keep
dataon a volume, otherwise retained messages and persistent sessions vanish when the container is recreated. - Put TLS on 8883 (and on the WebSocket listener) before exposing anything to the internet — see MQTT ports for the conventions.
- To debug, read
docker logs mosquittorather than runningmosquitto -vviadocker exec— that starts a second broker inside the container and fails with "address already in use".
Frequently asked questions
Why can I not connect to the Mosquitto Docker container from my host?
Without a mounted mosquitto.conf that defines a listener, Mosquitto 2.x runs in local only mode and only accepts connections from inside the container. Mount a config with listener 1883 and an authentication setting, and publish the port with -p 1883:1883.
How do I add a user to Mosquitto running in Docker?
Run mosquitto_passwd inside the container with docker exec, writing to a password file in the mounted config folder, then restart the container so the broker reloads the file.
Which ports does the eclipse-mosquitto image use?
Whatever listeners you configure. By convention 1883 is plain MQTT over TCP, 8883 is MQTT over TLS and 9001 is MQTT over WebSockets. Each must be defined in mosquitto.conf and published with Docker.