Skip to content

Secure MySQL config files and credentials

Severity: lowApplies to: MySQL 8.4 LTSApplies to: MariaDB 11.x / 12.x
The fix
Terminal window
sudo chown root:mysql /etc/mysql/my.cnf
sudo chmod 640 /etc/mysql/my.cnf
sudo chmod 640 /etc/mysql/mysql.conf.d/*.cnf
chmod 600 ~/.my.cnf
sudo chmod 750 /var/lib/mysql

Substitute mariadb.conf.d if that’s what you’re running.

Config files hold credentials in cleartext. ~/.my.cnf exists precisely so you can put a password in it, and my.cnf frequently grows a [client] section for the same reason. A world-readable one means every local account — every service user, every deployment agent, anything that gets a shell through an unrelated bug — can read the database password.

This is low because it needs local access first. It is on the list because it quietly undoes the work of every other page: a perfect grant model protected by a 644 file with the password in it isn’t protecting much.

This is the more interesting half, and it catches people who’d never chmod a config file wrong:

Terminal window
mysql -u app -phunter2 appdb # don't

Command lines are world-readable on Linux. Any user on the box can run ps aux — or read /proc/<pid>/cmdline — and see it while the process runs. MySQL warns about this (“Using a password on the command line interface can be insecure”), and the warning is routinely suppressed rather than heeded.

It’s worse in scripts, because the password then lives in the shell history, in CI logs, and in any process listing captured by monitoring.

MySQL ships the right answer, and it’s underused. mysql_config_editor writes an obfuscated credential file that the client reads automatically:

Terminal window
mysql_config_editor set --login-path=prod --host=10.0.1.5 --user=app --password
# prompts for the password, stores it in ~/.mylogin.cnf
mysql --login-path=prod appdb
mysqldump --login-path=prod appdb > backup.sql

Be precise about what this does: ~/.mylogin.cnf is obfuscated, not encrypted. Anyone who can read the file can recover the password — mysql_config_editor print --all does it for you. It is not a secret store.

What it genuinely buys you is that the password is never in a command line, never in shell history, and never in a CI log. Those are the leaks that actually happen. File permissions still do the real work, and mysql_config_editor sets the file to 600 itself.

MariaDB does not ship mysql_config_editor. Use a 600 option file with a [client] section and --defaults-file, which achieves the same thing minus the obfuscation.