Every MySQL breach I've seen comes down to the same five mistakes. Fix these and you're already ahead of most installations.
SQL Injection: Yeah, It's Still A Thing
Found SQL injection in a production app last week. Brand new React frontend hitting a Node API that just concatenated user input straight into queries.
-- This is what they had:
SELECT * FROM users WHERE email = '${userEmail}';
-- Works fine until someone enters: test@example.com'; DROP TABLE users;--
-- Then you have no users table and a very unhappy Monday morning
The developer said "but we validate the email format on the frontend." Sure, and I can disable JavaScript in about 2 seconds.
Same thing with JSON functions. Just because it says JSON doesn't mean it's magically safe from injection. JSON_EXTRACT() with user input is still user input going into SQL.
Default Passwords Are Everywhere
Check any MySQL server that's been running for more than six months. Guaranteed there's at least one account with a default password. Usually root with no password at all.
-- This works on more servers than it should:
mysql -u root -p
-- Just hit Enter when it asks for password
New MySQL versions use caching_sha2_password which is more secure, but it breaks old PHP applications. So instead of updating their code, developers just switch back to the weak authentication:
-- The "fix" I see everywhere:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
Yeah, they literally use "password" as the password. I've seen this in production.
Exposed MySQL Servers
Found a MySQL server bound to 0.0.0.0 last month during a security scan. Default root password, accessible from anywhere on the internet. When I asked about it, they said "oh that was just for testing."
The server had been running like that for over a year.
## What they had in my.cnf:
bind-address = 0.0.0.0
## What it should be:
bind-address = 127.0.0.1
Happens all the time. Developer can't connect from their machine, googles the error, finds a Stack Overflow answer that says to bind to 0.0.0.0, and never changes it back.
Everyone Gets SUPER Privileges
Half the MySQL servers I audit have application accounts with way too many permissions. Usually because someone was fixing a production issue at 2am and just granted everything to make it work.
-- The panic fix:
GRANT ALL PRIVILEGES ON *.* TO 'app_user'@'%';
-- "I'll fix this properly later" (they never do)
Your web application doesn't need to create databases or modify user accounts. Give it SELECT, INSERT, UPDATE, DELETE on the specific databases it needs. Nothing more.
The Test Database Nobody Deletes
MySQL creates a test database during installation that any user can access. It's supposed to be deleted after setup, but somehow never is.
-- Clean this up right now:
DROP DATABASE test;
DELETE FROM mysql.db WHERE db='test%';
FLUSH PRIVILEGES;
Found cryptocurrency miners running in test databases before. Also found backup copies of production data sitting there unencrypted because someone thought "it's just the test database."
What Actually Works in MySQL 8.4
Password Management
The dual password feature is actually useful. You can change a password without breaking every application connection:
-- Add new password, keep old one working
ALTER USER 'app_user'@'%' IDENTIFIED BY 'NewPassword123!' RETAIN CURRENT PASSWORD;
-- Deploy apps with new password, then remove old one
ALTER USER 'app_user'@'%' DISCARD OLD PASSWORD;
This has saved me from weekend maintenance windows.
Encryption Is Slow But Works
TDE (transparent data encryption) encrypts your data with AES-256. Applications don't need to change, but encrypting large tables locks them up while it runs.
Tried encrypting a production table once during business hours. Bad idea. Locked everything for about two hours while it processed.
Fix These Five Things or Get Fucked
MySQL security breaks down to the same five problems every single time:
- Default passwords - Change root, change everything
- Exposed to internet - bind-address = 127.0.0.1, not 0.0.0.0
- Too many privileges - Stop giving everyone SUPER privileges
- Test database - Delete it and those anonymous users
- No SSL - Force encrypted connections for production data
Fix these five things and you've prevented 95% of MySQL breaches. Everything else is compliance theater.
If auditors want documentation, MySQL 8.4 has checkboxes for whatever they're asking for. Most compliance requirements aren't technically challenging - they just want proof you're not completely incompetent.
Run mysql_secure_installation
after every fresh MySQL install. It's basic but fixes the obvious problems like anonymous users and the test database.
For everything else, the official MySQL security docs are actually decent once you skip the marketing fluff.