Summary
Running mosquitto --test-config -c <config> with built-in persistence enabled overwrites an existing persistence database with a new empty database, even though the command reports that the configuration is valid and is documented as not starting the broker.
This can silently remove retained messages, persistent client sessions, subscriptions, and queued client messages.
Environment
- Mosquitto broker:
2.1.2-0mosquitto1~bookworm1
- Mosquitto clients:
2.1.2-0mosquitto1~bookworm1
- Installed from the official Eclipse Mosquitto Debian repository
- OS: Debian GNU/Linux 12 (bookworm), amd64
- Runtime: unprivileged LXC container
- Persistence: built-in
mosquitto.db persistence, no persistence plugin
Minimal reproducer
Run as root on a system where the mosquitto user exists. It uses an isolated temporary directory and TCP port 28883.
#!/bin/sh
set -eu
workdir=$(mktemp -d /tmp/mosquitto-test-config.XXXXXX)
cleanup() {
if [ -f "$workdir/broker.pid" ]; then
kill "$(cat "$workdir/broker.pid")" 2>/dev/null || true
fi
rm -rf "$workdir"
}
trap cleanup EXIT INT TERM
mkdir "$workdir/data"
chown mosquitto:mosquitto "$workdir" "$workdir/data"
chmod 0750 "$workdir" "$workdir/data"
cat > "$workdir/mosquitto.conf" <<EOF
listener 28883 127.0.0.1
allow_anonymous true
persistence true
persistence_location $workdir/data/
log_dest stdout
EOF
chown mosquitto:mosquitto "$workdir/mosquitto.conf"
mosquitto -c "$workdir/mosquitto.conf" > "$workdir/broker.log" 2>&1 &
broker_pid=$!
printf '%s\n' "$broker_pid" > "$workdir/broker.pid"
sleep 1
mosquitto_pub -h 127.0.0.1 -p 28883 \
-t test/retained -m keep-me -r
kill "$broker_pid"
wait "$broker_pid"
rm "$workdir/broker.pid"
echo BEFORE
stat -c 'size=%s' "$workdir/data/mosquitto.db"
sha256sum "$workdir/data/mosquitto.db"
echo TEST_CONFIG
mosquitto --test-config -c "$workdir/mosquitto.conf"
echo AFTER
stat -c 'size=%s' "$workdir/data/mosquitto.db"
sha256sum "$workdir/data/mosquitto.db"
Actual result
BEFORE
size=164
febc9c816352b46407c8ce591a7f3c99b1b6ca985f84e0586666ebb573a23c73 .../data/mosquitto.db
TEST_CONFIG
1786540850: Configuration file is OK.
1786540850: mosquitto version 2.1.2 terminating
1786540850: Saving in-memory database to .../data//mosquitto.db.
AFTER
size=47
98569e29ce43ccf0d13743a099dd9e7d890a4e0b25cc8a8db3cfa081c9708364 .../data/mosquitto.db
The 47-byte file is an empty persistence database. The retained message is lost.
I first encountered this with a stopped production broker: a 2,407,332-byte persistence database was replaced by the same 47-byte empty database. I restored it from a snapshot, then reproduced the behavior independently with the script above.
Expected result
--test-config should only parse and validate the configuration. It should not create, truncate, replace, or otherwise modify the configured persistence database.
The current man page describes it as:
Load the config file specified with -c, and verify that it is valid but do not start the broker.
Possible cause
The output suggests that the --test-config path reaches normal shutdown persistence saving, but without first loading the existing persistence database. It therefore saves an empty in-memory database over the existing file.
Workaround
For now, configuration validation can be performed against a copied configuration with either:
or a temporary persistence_location. Backing up mosquitto.db before using --test-config also prevents permanent data loss.
Summary
Running
mosquitto --test-config -c <config>with built-in persistence enabled overwrites an existing persistence database with a new empty database, even though the command reports that the configuration is valid and is documented as not starting the broker.This can silently remove retained messages, persistent client sessions, subscriptions, and queued client messages.
Environment
2.1.2-0mosquitto1~bookworm12.1.2-0mosquitto1~bookworm1mosquitto.dbpersistence, no persistence pluginMinimal reproducer
Run as root on a system where the
mosquittouser exists. It uses an isolated temporary directory and TCP port 28883.Actual result
The 47-byte file is an empty persistence database. The retained message is lost.
I first encountered this with a stopped production broker: a 2,407,332-byte persistence database was replaced by the same 47-byte empty database. I restored it from a snapshot, then reproduced the behavior independently with the script above.
Expected result
--test-configshould only parse and validate the configuration. It should not create, truncate, replace, or otherwise modify the configured persistence database.The current man page describes it as:
Possible cause
The output suggests that the
--test-configpath reaches normal shutdown persistence saving, but without first loading the existing persistence database. It therefore saves an empty in-memory database over the existing file.Workaround
For now, configuration validation can be performed against a copied configuration with either:
or a temporary
persistence_location. Backing upmosquitto.dbbefore using--test-configalso prevents permanent data loss.