Description:
A named `RESET PERSIST variable_name` removes the variable from the in-memory
persisted-variable maps and calls `flush_to_file()`, but ignores that function's
error return. If the backup file cannot be opened, written, synchronized, or
renamed, the SQL statement can report success even though `mysqld-auto.cnf`
still contains the supposedly removed setting.
This was reproduced in MySQL Community Server 8.4.11 by placing a directory at
the exact backup-file path before executing `RESET PERSIST max_connections`.
The statement returned exit status 0 with no warning, while the persistence
file remained byte-for-byte unchanged and retained `max_connections=222`.
How to repeat:
The following uses a disposable, digest-pinned container and a tmpfs data
directory. It does not modify an existing MySQL installation.
```bash
set -eu
IMG='mysql@sha256:85b9bf2e29cf836ecb8c2a15a935d4ba0c606631dff1dd79531a11983c638f2a'
C="mysql-my18-poc-$$"
docker run -d --name "$C" --label "edbf.owner=$C" \
--network none --read-only --cap-drop ALL \
--security-opt no-new-privileges=true --pids-limit 512 \
--memory 2048m --cpus 2 --user 999:999 \
--tmpfs /var/lib/mysql:rw,noexec,nosuid,nodev,size=1024m,uid=999,gid=999 \
--tmpfs /var/run/mysqld:rw,noexec,nosuid,nodev,size=16m,uid=999,gid=999 \
--tmpfs /tmp:rw,noexec,nosuid,nodev,size=128m,uid=999,gid=999 \
-e MYSQL_ALLOW_EMPTY_PASSWORD=yes \
"$IMG" --skip-name-resolve --log-error=/var/lib/mysql/error.log
trap 'docker rm -f "$C" >/dev/null 2>&1 || true' EXIT
for i in $(seq 1 120); do
test "$(docker exec "$C" mysql -uroot \
--socket=/var/run/mysqld/mysqld.sock -Nse 'SELECT @@port' 2>/dev/null)" = 3306 && break
sleep 1
done
test "$(docker exec "$C" mysql -uroot \
--socket=/var/run/mysqld/mysqld.sock -Nse 'SELECT @@port')" = 3306
docker exec "$C" mysql -uroot --socket=/var/run/mysqld/mysqld.sock \
-e 'SET PERSIST max_connections=222;'
BEFORE=$(docker exec "$C" cat /var/lib/mysql/mysqld-auto.cnf)
printf 'before=%s\n' "$BEFORE"
# Force only the next backup-file open to fail: this path should be a file,
# but mkdir makes it an existing directory.
docker exec --user 0:0 "$C" mkdir /var/lib/mysql/mysqld-auto.cnf.backup
set +e
RESET_OUTPUT=$(docker exec "$C" mysql -uroot \
--socket=/var/run/mysqld/mysqld.sock --batch --raw \
-e 'RESET PERSIST max_connections; SHOW WARNINGS;' 2>&1)
RESET_RC=$?
set -e
AFTER=$(docker exec "$C" cat /var/lib/mysql/mysqld-auto.cnf)
printf 'reset_rc=%s\nreset_output=%s\n' "$RESET_RC" "$RESET_OUTPUT"
if [ "$BEFORE" = "$AFTER" ]; then echo 'file_unchanged=yes'; else echo 'file_unchanged=no'; fi
printf '%s\n' "$AFTER" | grep -o '"max_connections"[^}]*}'
```
## Actual result
The official 8.4.11 run returned:
```text
reset_rc=0
reset_output=
file_unchanged=yes
"max_connections": {"Value": "222", ...}
```
The original and final `mysqld-auto.cnf` contents were byte-identical. The
statement reported success and `SHOW WARNINGS` produced nothing, despite the
failed persistence update. The server remained healthy. The retained machine
record has SHA-256
`ec53368f441922236a6b2f5dac560ea466edcb8431f2aa20948c966d45ed1cf7`.
## Expected result
If the persisted configuration cannot be durably rewritten, `RESET PERSIST`
should return an error and must not report that the setting was removed.
Alternatively, the in-memory removal should be rolled back before returning an
error so memory and disk remain consistent.
Description: A named `RESET PERSIST variable_name` removes the variable from the in-memory persisted-variable maps and calls `flush_to_file()`, but ignores that function's error return. If the backup file cannot be opened, written, synchronized, or renamed, the SQL statement can report success even though `mysqld-auto.cnf` still contains the supposedly removed setting. This was reproduced in MySQL Community Server 8.4.11 by placing a directory at the exact backup-file path before executing `RESET PERSIST max_connections`. The statement returned exit status 0 with no warning, while the persistence file remained byte-for-byte unchanged and retained `max_connections=222`. How to repeat: The following uses a disposable, digest-pinned container and a tmpfs data directory. It does not modify an existing MySQL installation. ```bash set -eu IMG='mysql@sha256:85b9bf2e29cf836ecb8c2a15a935d4ba0c606631dff1dd79531a11983c638f2a' C="mysql-my18-poc-$$" docker run -d --name "$C" --label "edbf.owner=$C" \ --network none --read-only --cap-drop ALL \ --security-opt no-new-privileges=true --pids-limit 512 \ --memory 2048m --cpus 2 --user 999:999 \ --tmpfs /var/lib/mysql:rw,noexec,nosuid,nodev,size=1024m,uid=999,gid=999 \ --tmpfs /var/run/mysqld:rw,noexec,nosuid,nodev,size=16m,uid=999,gid=999 \ --tmpfs /tmp:rw,noexec,nosuid,nodev,size=128m,uid=999,gid=999 \ -e MYSQL_ALLOW_EMPTY_PASSWORD=yes \ "$IMG" --skip-name-resolve --log-error=/var/lib/mysql/error.log trap 'docker rm -f "$C" >/dev/null 2>&1 || true' EXIT for i in $(seq 1 120); do test "$(docker exec "$C" mysql -uroot \ --socket=/var/run/mysqld/mysqld.sock -Nse 'SELECT @@port' 2>/dev/null)" = 3306 && break sleep 1 done test "$(docker exec "$C" mysql -uroot \ --socket=/var/run/mysqld/mysqld.sock -Nse 'SELECT @@port')" = 3306 docker exec "$C" mysql -uroot --socket=/var/run/mysqld/mysqld.sock \ -e 'SET PERSIST max_connections=222;' BEFORE=$(docker exec "$C" cat /var/lib/mysql/mysqld-auto.cnf) printf 'before=%s\n' "$BEFORE" # Force only the next backup-file open to fail: this path should be a file, # but mkdir makes it an existing directory. docker exec --user 0:0 "$C" mkdir /var/lib/mysql/mysqld-auto.cnf.backup set +e RESET_OUTPUT=$(docker exec "$C" mysql -uroot \ --socket=/var/run/mysqld/mysqld.sock --batch --raw \ -e 'RESET PERSIST max_connections; SHOW WARNINGS;' 2>&1) RESET_RC=$? set -e AFTER=$(docker exec "$C" cat /var/lib/mysql/mysqld-auto.cnf) printf 'reset_rc=%s\nreset_output=%s\n' "$RESET_RC" "$RESET_OUTPUT" if [ "$BEFORE" = "$AFTER" ]; then echo 'file_unchanged=yes'; else echo 'file_unchanged=no'; fi printf '%s\n' "$AFTER" | grep -o '"max_connections"[^}]*}' ``` ## Actual result The official 8.4.11 run returned: ```text reset_rc=0 reset_output= file_unchanged=yes "max_connections": {"Value": "222", ...} ``` The original and final `mysqld-auto.cnf` contents were byte-identical. The statement reported success and `SHOW WARNINGS` produced nothing, despite the failed persistence update. The server remained healthy. The retained machine record has SHA-256 `ec53368f441922236a6b2f5dac560ea466edcb8431f2aa20948c966d45ed1cf7`. ## Expected result If the persisted configuration cannot be durably rewritten, `RESET PERSIST` should return an error and must not report that the setting was removed. Alternatively, the in-memory removal should be rolled back before returning an error so memory and disk remain consistent.