Database audit fix

How to Check and Secure MySQL Root Password on Linux

A MySQL or MariaDB root account with no password makes every local Linux user a database administrator. Test it by running mysql --no-defaults -u root from an unprivileged shell, then set a password or move root to socket authentication.

Hiren KalariyaLast reviewed: Aug 30, 2026Check mysql-root-password
High
severity
Yes
needs root or sudo
4
results it can return
1 of 8
checks in this audit

Every threshold on this page is transcribed from the database-security-authentication audit script that CtrlOps runs, and a build check fails if the two ever disagree. See all 8 Authentication checks, or how the audit runs.

High severityNeeds sudo

What this check reads

Runs, as the unprivileged audit user, MYSQL_PWD= mysql --no-defaults -u root -e 'SELECT 1'. --no-defaults ignores ~/.my.cnf, and the empty MYSQL_PWD clears any inherited password, so the only way this succeeds is if root@localhost has no password and uses a password plugin (not auth_socket/unix_socket). Success is the failure condition: if that command exits zero the check reports FAIL, and it is only attempted when the audit itself is not running as UID 0. If that login fails but the root-shell login (MYOK) works, root access is gated by the OS (socket auth) or by a password, and the check reports PASS.

When it applies

Runs only when MySQL or MariaDB is detected on the host (HAS_MY=1: a mysql/mysqld binary, a running mysqld/mariadbd, matching the shared engine probe). The FAIL branch is only reachable when the audit runs as a non-root user - as UID 0 the passwordless probe is skipped because socket auth would make it succeed regardless. The PASS branch needs MYOK=1, i.e. root or sudo to reach the socket. Containerised MySQL is invisible to this check.

What each result means

Result thresholds this check applies
ResultWhenWhat it means
SKIPMySQL/MariaDB not detectedNothing was tested. No MySQL or MariaDB was found on this host, which is not the same as a database that passed.
FAILNon-root shell logged in as MySQL root with no passwordEvery local account on this server is already a database administrator. Set a root password or move root to socket authentication.
PASSPasswordless login failed and root-shell access worksAn ordinary shell cannot become MySQL root without a credential.
SKIPNeither worked: server down, or sudo needed to reach the socketNothing was verified. The server could not be reached, so treat root as unchecked rather than safe.

Why it matters

OWASP Database Security Cheat Sheet: always require authentication, including for local connections. A passwordless root@localhost means every Linux account on the host (including the web server user after an RCE) has full DBA rights. CIS MySQL Benchmark: "Ensure no users have an empty password" / "Ensure 'root' has a strong password or uses socket authentication".

Why it fails, and when it is wrong

  • Fresh Ubuntu/Debian MariaDB installs use unix_socket for root and will PASS. MySQL 8 on Ubuntu uses auth_socket for root and will PASS. Manually created installs (Docker entrypoints, old distros) often leave root with no password.
  • If the audit itself runs as UID 0 the passwordless probe is skipped (it would succeed via socket auth), so root-run audits cannot detect this case; they rely on mysql-passwordless-accounts.
  • SKIP "not accessible": mysqld is stopped, the socket path differs from the client default (/var/run/mysqld/mysqld.sock vs /tmp/mysql.sock), or the audit account has no sudo.
  • Containerised MySQL is not seen by the host probe.

How to fix it

Probe from an unprivileged shell

As a non-root user, this must fail. If it succeeds, root has no password and every local account on the host already owns the database.

mysql --no-defaults -u root -e 'SELECT 1'

Set a password

ALTER USER 'root'@'localhost' IDENTIFIED BY 'long-random-password';
FLUSH PRIVILEGES;

Or run mysql_secure_installation (MariaDB: mariadb-secure-installation), which walks the same change interactively.

Or use socket authentication instead

Recommended for local admin use: root logs in only when the OS user is already root, so there is no shared secret to rotate, store or leak.

ALTER USER 'root'@'localhost' IDENTIFIED WITH auth_socket;        -- MySQL
ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket;          -- MariaDB

Re-run the probe

Repeat step 1 as an ordinary user. The passwordless login must now be refused.

Verify the fix

# As an unprivileged user, a passwordless root login must be refused:
MYSQL_PWD= mysql --no-defaults -u root -e 'SELECT 1'
# expected: ERROR 1045 (access denied) or ERROR 1698 (auth_socket in use)

# Confirm which plugin root now uses:
sudo mysql -N -e "SELECT user,host,plugin FROM mysql.user WHERE user='root'"
# expected: auth_socket / unix_socket, or a password plugin with a non-empty authentication_string

Debugging

The engine probe found no client binary and no running server. Unlike the PostgreSQL, MongoDB and Redis probes it never looks for a config file, so HAS_MY depends entirely on mysql/mysqld being on PATH or mysqld/mariadbd being up. Confirm with command -v mysql mysqld mariadbd; pgrep -a mysqld mariadbd. If the database runs in a container, this check cannot see it; audit it from inside (docker exec -it <c> mysql ...) or use the Docker checks.

mysqld is stopped, or the audit account cannot reach the socket. Test the exact command the script runs: sudo mysql -N -e 'SELECT 1'. A "Can't connect through socket" error usually means the client default socket path (/var/run/mysqld/mysqld.sock) differs from the server's; compare with sudo mysqladmin variables | grep -w socket. If it is a sudo problem, see the privilege note in Script context.

Reproduce it verbatim as the audit user: MYSQL_PWD= mysql --no-defaults -u root -e 'SELECT 1'. If that succeeds, the finding is real; --no-defaults means a password in ~/.my.cnf is not what let it in.

Expected: the passwordless probe is skipped for UID 0. Re-run the probe as an ordinary user, or rely on the MySQL Passwordless Accounts check.

Sources

How the script reads this

Next

Re-run the Authentication audit after applying the fix and confirm this check moves to PASS. CtrlOps runs all 8 checks over your existing SSH connection and scores the result, so the change is visible without reading another config file.

All 8 Authentication fixes
Audit your fleet

Find every one of these on every server, in one click

CtrlOps runs this audit over your existing SSH connection - no agents, no scripts to manage. $7/user/month after a 1 month free trial - no credit card required.

✓ Start instantly·✓ No credit card·✓ No sneaky autorenewals