MySQL exposed to the internet
MySQL on a public IP is a brute-force target with no rate limiting and no account lockout. It will answer authentication attempts as fast as they arrive, indefinitely, and internet-wide scanning finds port 3306 within minutes of it becoming routable.
That much is expected. What makes it worse than it sounds is what a successful login reaches.
A login is not confined to the database
Section titled “A login is not confined to the database”Three escalation paths, in the order attackers try them:
FILE privilege → read and write files. An account with FILE can read any
file the mysql OS user can read, and write files anywhere it can write:
SELECT LOAD_FILE('/etc/passwd');SELECT '<?php system($_GET[0]); ?>' INTO OUTFILE '/var/www/html/x.php';That’s a web shell, from a database login.
secure_file_priv is what stops it.
UDF → arbitrary code. With FILE and INSERT on mysql, an attacker writes
a shared object into the plugin directory and registers it as a user-defined
function. The function then executes native code inside the mysqld process, as
the mysql user. This is the classic MySQL RCE and it needs no vulnerability —
only privileges.
Credentials for everything else. The mysql.user table holds password
hashes. On mysql_native_password those are
unsalted SHA-1 — cheap to crack offline, and people reuse database passwords.
So “there’s nothing sensitive in that database” is the wrong question, the same way it is for Redis and Postgres. The data is not the prize. The host is.
What actually gets servers compromised
Section titled “What actually gets servers compromised”Roughly in order:
- A weak password on an account with
'%'as its host — reachable from anywhere, and guessable. GRANT ALL ON *.*, so the account that fell hasFILEand the UDF path is open.- An anonymous account left over from a legacy install — no password required at all.
- An EOL server. MySQL 8.0 reached end of life in April 2026 and gets no further security fixes.
Notice that none of these are exotic. They’re the defaults of a setup that was made to work quickly.
The shortest path from exposed to closed
Section titled “The shortest path from exposed to closed”- Bind to a private interface, or
skip-networkingif nothing connects over TCP. This alone closes it. - Firewall 3306 — and 33060 if MySQL’s X Protocol is running.
- Remove
'%'hosts andFILE/SUPERfrom applications — bounds what a fallen credential reaches. - Set
secure_file_priv = NULL— closes both the web-shell and UDF paths even if a grant is wrong.
Steps 1 and 2 take two minutes.
Related
Section titled “Related”- Hardening MySQL and MariaDB — the full checklist.
- Restrict file privileges — the control that closes the escalation.