Remove anonymous users and the test database
-- Anonymous accounts: no username, no passwordSELECT user, host FROM mysql.user WHERE user = '';DROP USER ''@'localhost';DROP USER ''@'%'; -- if present
-- The test database, writable by anyoneDROP DATABASE IF EXISTS test;DELETE FROM mysql.db WHERE db IN ('test', 'test\\_%');
-- Remote rootSELECT user, host FROM mysql.user WHERE user = 'root' AND host NOT IN ('localhost','127.0.0.1','::1');
FLUSH PRIVILEGES;Why it matters
Section titled “Why it matters”Anonymous accounts have an empty username and an empty password. Anyone who
can reach the server connects as ''@'localhost' with no credentials at all.
Historically MySQL created them at install so that a fresh server was immediately
usable, and the account has a nasty second property: because MySQL sorts accounts
by specificity, an anonymous entry for '%' can shadow a real named account,
so myapp connects as anonymous and then gets permission errors that make no
sense.
The test database was created with grants in mysql.db allowing any
user — including anonymous — to create tables and write data in it. That’s a
foothold: somewhere to stage data, somewhere to write, and on an install with
FILE privileges intact, somewhere to build
from.
This is mostly about upgraded and legacy servers
Section titled “This is mostly about upgraded and legacy servers”Be clear about scope, because a fresh install may already be fine:
- A fresh MySQL 8.4 initialised with
mysqld --initializecreates no anonymous users and no test database. Nothing to do. - A server upgraded from 5.x, or built from an old image, or provisioned by an automation template written years ago, very often still has them. Upgrades don’t remove accounts.
- MariaDB on some packagings still creates them.
So the version number doesn’t answer this — the mysql.user table does. That’s a
three-second query and worth running even if you’re confident.
mysql_secure_installation is not a complete answer
Section titled “mysql_secure_installation is not a complete answer”mysql_secure_installation is the standard recommendation and it does handle
these. Two caveats worth knowing:
It is interactive and one-shot, so it can’t be part of configuration management, and nothing re-checks afterwards. An account added later by a migration script or a restored dump is invisible to it.
It also only ever ran on the server where someone remembered to run it. On a fleet, “we ran mysql_secure_installation” is a claim about one afternoon, not an ongoing property. The queries in the verify block are what you want in a periodic check.
Related
Section titled “Related”- Authentication plugins — for the accounts you keep.
- Grant least privilege — what those accounts should be able to do.