`mosquitto_passwd` produces misleading errors and instructions in docker environment
I'd like to try to draw together the threads of several issues in the hope of getting this problem fixed because it's quite scary for first-time users who don't know it's all bogus.
To summarise, in a docker environment:
-
The broker runs as user ID 1883;
-
docker-entrypoint.shenforces 1883:1883 ownership on/mosquittoat each launch, which includes any password file located within that scope; -
The
mosquitto_passwordutility hates this and keeps displaying these errors:arning: File /mosquitto/config/pwfile owner is not root. Future versions will refuse to load this file. arning: File /mosquitto/config/pwfile group is not root. Future versions will refuse to load this file.The utility also displays these instructions:
o fix this, use `chown root /mosquitto/config/pwfile`.
It should be self-evident that if:
- The broker is running as user ID 1883; and
- The password file is initialised with mode 600; and
- The password file is owned by root,
then the broker would not be able to read the password file. It is only because docker-entrypoint.sh enforces 1883:1883 on each launch or restart that the broker is able to read the password file. But that then causes mosquitto_passwd to moan and complain the next time it is used.
The issues I believe are directly related to this are:
- #2890 (2023-09-09)
- #2923 (2023-10-14) (my issue)
- #2925 (2023-10-17)
- #3213 (2024-02-15)
Possibly related issues:
- #3041 (2024-04-17)
- #3131 (2024-10-10)
- #3263 (2025-04-28)
For the avoidance of doubt, please let me demonstrate the problem.
A script named setup-mosquitto-test.sh to initialise a test environment (I'm hoping to avoid any "can't duplicate" problems):
#!/usr/bin/env bash
# the action occurs here
TEST_DIR="${HOME}/mosquitto-test"
# create the directory
mkdir -p "${TEST_DIR}"
# make that the working directory
cd "${TEST_DIR}"
# the persistent store is at the relative path
PERSIST="./volumes/mosquitto"
# create the structure of the persistent store
mkdir -p "${PERSIST}"
(cd "${PERSIST}" ; mkdir config data log)
# copy mosquitto configuration into place
cat <<-CONFIG_EOT >"${PERSIST}/config/mosquitto.conf"
listener 1883
persistence true
persistence_location /mosquitto/data
log_dest stdout
#password_file /mosquitto/config/pwfile
allow_anonymous true
CONFIG_EOT
# copy compose file into place
cat <<-COMPOSE_EOT >"docker-compose.yml"
---
services:
mosquitto:
container_name: mosquitto
image: eclipse-mosquitto:latest
restart: unless-stopped
ports:
- "1883:1883"
volumes:
- ${PERSIST}/config:/mosquitto/config
- ${PERSIST}/data:/mosquitto/data
- ${PERSIST}/log:/mosquitto/log
COMPOSE_EOT
On the target system:
$ ./setup-mosquitto-test.sh
$ cd mosquitto-test
$ tree -apug
[drwxr-xr-x pi pi ] .
├── [-rw-r--r-- pi pi ] docker-compose.yml
└── [drwxr-xr-x pi pi ] volumes
└── [drwxr-xr-x pi pi ] mosquitto
├── [drwxr-xr-x pi pi ] config
│ └── [-rw-r--r-- pi pi ] mosquitto.conf
├── [drwxr-xr-x pi pi ] data
└── [drwxr-xr-x pi pi ] log
The starting point is all components are owned by $USER.
Start the broker:
$ docker compose up -d
[+] Running 2/2
✔ Network mosquitto-test_default Created 0.2s
✔ Container mosquitto Started 0.6s
$ docker logs mosquitto
1749358165: mosquitto version 2.0.21 starting
1749358165: Config loaded from /mosquitto/config/mosquitto.conf.
1749358165: Opening ipv4 listen socket on port 1883.
1749358165: Opening ipv6 listen socket on port 1883.
1749358165: mosquitto version 2.0.21 running
$ docker top mosquitto -o pid,euser,ruser,suser,fuser,comm
PID EUSER RUSER SUSER FUSER COMMAND
1137908 1883 1883 1883 1883 mosquitto
Broker has launched without error and is running as UID 1883.
$ tree -apug
[drwxr-xr-x pi pi ] .
├── [-rw-r--r-- pi pi ] docker-compose.yml
└── [drwxr-xr-x pi pi ] volumes
└── [drwxr-xr-x pi pi ] mosquitto
├── [drwxr-xr-x 1883 1883 ] config
│ └── [-rw-r--r-- 1883 1883 ] mosquitto.conf
├── [drwxr-xr-x 1883 1883 ] data
└── [drwxr-xr-x 1883 1883 ] log
Content of bind-mount volumes is owned by UID 1883. This is by virtue of:
Create the first password:
$ docker exec mosquitto mosquitto_passwd -c -b /mosquitto/config/pwfile user1 password1
$ tree -apug
[drwxr-xr-x pi pi ] .
├── [-rw-r--r-- pi pi ] docker-compose.yml
└── [drwxr-xr-x pi pi ] volumes
└── [drwxr-xr-x pi pi ] mosquitto
├── [drwxr-xr-x 1883 1883 ] config
│ ├── [-rw-r--r-- 1883 1883 ] mosquitto.conf
│ └── [-rw------- root root ] pwfile
├── [drwxr-xr-x 1883 1883 ] data
│ └── [-rw------- 1883 1883 ] mosquitto.db
└── [drwxr-xr-x 1883 1883 ] log
pwfile created, owned by root, read/write only by root.
Activate password support:
$ CONFIG="./volumes/mosquitto/config/mosquitto.conf"
$ grep password_file "${CONFIG}"
#password_file /mosquitto/config/pwfile
$ sudo sed -i "s/^#\(password_file\)/\1/" "${CONFIG}"
$ grep password_file "${CONFIG}"
password_file /mosquitto/config/pwfile
$ docker compose restart mosquitto
[+] Restarting 1/1
✔ Container mosquitto Started 0.9s
Start a background subscriber process (no credentials):
$ mosquitto_sub -h localhost -t test -F "SUB: %I %t %p" &
[1] 1140506
Publish a message:
$ mosquitto_pub -h localhost -t test -m "$(date)" -u user1 -P password1
SUB: 2025-06-08T15:04:33+1000 test Sun Jun 8 03:04:33 PM AEST 2025
$
Conclusion: password support is active (in parallel with anonymous access, which is what the background listener is relying on).
Create another user:
$ docker exec mosquitto mosquitto_passwd -b /mosquitto/config/pwfile user2 password2
Warning: File /mosquitto/config/pwfile owner is not root. Future versions will refuse to load this file.To fix this, use `chown root /mosquitto/config/pwfile`.
Warning: File /mosquitto/config/pwfile group is not root. Future versions will refuse to load this file.
formatting fixed to be a little more human-readable than that which is actually produced by
mosquitto_passwd
Respond to the instruction buried in the middle of the scary message (slightly enhanced to root:root):
$ PWFILE="./volumes/mosquitto/config/pwfile"
$ ls -l "${PWFILE}"
-rw------- 1 1883 1883 238 Jun 8 15:06 ./volumes/mosquitto/config/pwfile
$ sudo chown root:root "${PWFILE}"
$ ls -l "${PWFILE}"
-rw------- 1 root root 238 Jun 8 15:06 ./volumes/mosquitto/config/pwfile
Add a third set of credentials:
$ docker exec mosquitto mosquitto_passwd -b /mosquitto/config/pwfile user3 password3
$
No errors - so mosquitto_passwd is happy but, of course, the credentials for users 2 and 3 are not yet active. Proof:
$ mosquitto_pub -h localhost -t test -m "$(date)" -u user2 -P password2
Connection error: Connection Refused: not authorised.
Error: The connection was refused.
$ mosquitto_pub -h localhost -t test -m "$(date)" -u user3 -P password3
Connection error: Connection Refused: not authorised.
Error: The connection was refused.
The new credentials won't be in effect until the container restarts or is re-created:
$ docker compose restart mosquitto
[+] Restarting 1/1
✔ Container mosquitto Started 0.8s
$ mosquitto_pub -h localhost -t test -m "$(date)" -u user2 -P password2
SUB: 2025-06-08T15:14:51+1000 test Sun Jun 8 03:14:51 PM AEST 2025
So the new credentials are working but, of course, ownership on pwfile has been put back to 1883:
$ ls -l "${PWFILE}"
-rw------- 1 1883 1883 357 Jun 8 15:11 ./volumes/mosquitto/config/pwfile
which, in turn, means the next manipulation of the password file will cause more misleading grizzles and instructions:
$ docker exec mosquitto mosquitto_passwd -b /mosquitto/config/pwfile user4 password4
Warning: File /mosquitto/config/pwfile owner is not root. Future versions will refuse to load this file.To fix this, use `chown root /mosquitto/config/pwfile`.
Warning: File /mosquitto/config/pwfile group is not root. Future versions will refuse to load this file.
Rinse, repeat. Ad infinitum. Ad nauseam. The ultimate no-win.
It also does this not in a docker environment
After hours of poking (like so many of us here), I finally got it working. I am not at all a Linux expert, but I can describe what I did last:
TL;DR Use your NAS admin user to create the container.
- SSH on my Synology and delete the mosquitto container files from previously unsuccessful trials: "rm -r mosquitto"
- Log in on Synology with the Admin user. Previously, I inadvertedly used my personal user and the admin user was deactivated as it is good practice. I believe this was the game changer.
- Create the Container from the Image using the Synology container manager. 3a. Create (and map) the folders "/mosquitto/mosquitto/config", "/mosquitto/mosquitto/data", "/mosquitto/mosquitto/log". Previously, I had "/mosquitto/config", etc. - not sure if this matters. Just mentioning, since this was the 2nd thing I changed and maybe, this is the game changer. Not sure, as I said.
- In the terminal window, enter the container with "sudo docker exec -it -u root eclipse-mosquitto sh" 4a. Copy "mosquitto-no-auth.conf" to "/mosquitto/mosquitto/config/mosquitto.conf"
- Log in on Synology with my personal user and re-start the Container.
- Bingo - it connected to my heat pump without intervention (as shown in the Synology log file) and anonymous MQTT-Explorer login from http://192.168.178.178:4000/ (same IP as Synology) worked as well.
- Side-note: I have not created any file outside or inside the container. I re-used the provided "mosquitto-no-auth.conf" which I copied without modifying.
Looking around in the linux folders from outside the Container: /volume1/docker/mosquitto and all sub-folders ("/mosquitto" with "/config", "/data", "/log") have "777 admin users". The sub-folders appear empty.
Looking around in the linux folders from inside the Container:
- /volume1/docker/mosquitto and all sub-folders ("/mosquitto" with "/config", "/data", "/log") have "755 mosquitto mosquitto"
- /mosquitto/config/mosquitto.conf has "644 mosquitto mosquitto"
One other thing probably not to do (my friend told me, and I ignored for too long, apologies, Daniel!): As a windows user, I mapped the "/config" folder to a windows drive, so I could use Notepad++ instead of vi to edit the mosquitto.conf . This file does not exist -or if it does probably messes up everything- on Linux outside the container.
While I wrote this post, MQTT-Explorer reported that my shower water temperature has increased from 48°C to 52°C. I should have a beer.
Thanks @Greentreegarden for mentioning and for "poking" around😁
TL;DR My above explanation is correct. You must observe to act as the correct user (as described above).
I updated the mosquitto container in the Synology container manager today. Guess what - "Starting in local only mode" appeared in the log file again and MQTT-Explorer would not connect.
I followed my guideline above, but in # 5 wrongly restarted the container with the Synology admin user (red # 1 in screenshot). The problem remained and MQTT-Explorer did not connect. After restarting the Synology container with my personal user (red # 2 in screenshot, as described correctly above), previously connected clients reconnected.