mosquitto icon indicating copy to clipboard operation
mosquitto copied to clipboard

`mosquitto_passwd` produces misleading errors and instructions in docker environment

Open Paraphraser opened this issue 8 months ago • 4 comments

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.sh enforces 1883:1883 ownership on /mosquitto at each launch, which includes any password file located within that scope;

  • The mosquitto_password utility 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:

  1. The broker is running as user ID 1883; and
  2. The password file is initialised with mode 600; and
  3. 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.

Paraphraser avatar Jun 08 '25 06:06 Paraphraser

It also does this not in a docker environment

LeePorte avatar Oct 17 '25 10:10 LeePorte

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.

  1. SSH on my Synology and delete the mosquitto container files from previously unsuccessful trials: "rm -r mosquitto"
  2. 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.
  3. 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.
  4. 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"
  5. Log in on Synology with my personal user and re-start the Container.
  6. 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.
  7. 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.

Greentreegarden avatar Oct 29 '25 09:10 Greentreegarden

Thanks @Greentreegarden for mentioning and for "poking" around😁

DanielMisch avatar Oct 29 '25 10:10 DanielMisch

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.

Image

Greentreegarden avatar Nov 23 '25 16:11 Greentreegarden