The Same Five Fuckups, Every Time

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:

  1. Default passwords - Change root, change everything
  2. Exposed to internet - bind-address = 127.0.0.1, not 0.0.0.0
  3. Too many privileges - Stop giving everyone SUPER privileges
  4. Test database - Delete it and those anonymous users
  5. 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.

MySQL Security Features Comparison

Security Feature

MySQL 8.4 LTS

MySQL 8.0

MySQL 5.7 (EOL)

Enterprise vs Community

Authentication

caching_sha2_password

✅ Default

✅ Default

Both editions

Account locking

✅ Enhanced

✅ Basic

Both editions

Password validation

✅ Component

✅ Plugin

✅ Plugin

Both editions

Dual password support

✅ Since 8.0.14

Both editions

Failed login tracking

✅ Built-in

✅ Since 8.0.19

Both editions

Encryption

Data-at-rest (TDE)

✅ Enhanced

✅ InnoDB only

Enterprise only

Automatic key rotation

Enterprise only

Binlog encryption

✅ Default

✅ Manual

Both editions

Redo/Undo log encryption

Both editions

Connection Security

TLS 1.3 support

✅ Since 8.0.16

❌ TLS 1.2 max

Both editions

Certificate-based auth

✅ Enhanced

✅ Basic

Both editions

Automatic cert generation

Both editions

Access Control

Roles

✅ Enhanced

Both editions

Dynamic privileges

Both editions

Partial revokes

✅ Since 8.0.16

Both editions

Auditing

Enterprise Audit

✅ Enhanced

Enterprise only

General query log

Both editions

Error log filtering

✅ Since 8.0.4

Both editions

Monitoring

Performance Schema security

✅ Enhanced

✅ Basic

Both editions

Security-related status vars

✅ Limited

Both editions

Firewall Protection

Enterprise Firewall

✅ Enhanced

Enterprise only

Connection rate limiting

Both editions

Data Masking

Enterprise Data Masking

Enterprise only

Backup Security

Enterprise Backup encryption

Enterprise only

Support & Patches

Security patches

✅ Until 2032

✅ Until 2026

❌ EOL Oct 2025

Enterprise priority

Extended support

Enterprise only

User Management: Stop Overthinking This Shit

Most authentication problems: weak passwords and dead accounts from people who left the company. Fix these two things before you worry about anything else.

Password Policies That Actually Work

Password Expiration Breaks Things
Password expiration sounds good until service accounts start failing because their passwords expired. Got woken up at 3am once because our monitoring system couldn't connect to the database.

-- Service accounts should never expire:
CREATE USER 'app_user'@'localhost'
  IDENTIFIED BY 'ActuallySecurePassword2025!'
  PASSWORD EXPIRE NEVER;

-- Human accounts can expire:
ALTER USER 'admin'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;

Test password expiration in a staging environment that actually looks like production. Most "staging" environments are just developer laptops.

The Dual Password Thing Is Useful
This lets you change passwords without breaking everything:

-- Add new password, keep old one working
ALTER USER 'app'@'%' IDENTIFIED BY 'NewPass!' RETAIN CURRENT PASSWORD;
-- Update half your apps, test, update the rest
-- Then remove old password
ALTER USER 'app'@'%' DISCARD OLD PASSWORD;

Actually saved me from weekend maintenance windows.

User Account Cleanup

Check for old accounts regularly. Found accounts for contractors who left years ago still active with full database access.

-- Find accounts that haven't logged in recently
SELECT user, host,
       IFNULL(last_login, 'Never') as last_login
FROM performance_schema.accounts
WHERE user NOT IN ('mysql.sys', 'mysql.session');

Delete accounts you don't recognize. Better to break something and fix it than leave backdoors open.

Roles Make Life Easier

MySQL roles let you group permissions instead of managing them per user. Useful when you have more than a few people.

-- Create roles for different job functions
CREATE ROLE 'read_only_user';
CREATE ROLE 'app_user';
CREATE ROLE 'admin_user';

-- Grant permissions to roles
GRANT SELECT ON production_db.* TO 'read_only_user';
GRANT SELECT, INSERT, UPDATE, DELETE ON production_db.* TO 'app_user';
GRANT ALL PRIVILEGES ON *.* TO 'admin_user';

-- Assign roles to users
CREATE USER 'john'@'%' IDENTIFIED BY 'SecurePass123!';
GRANT 'read_only_user' TO 'john'@'%';
SET DEFAULT ROLE 'read_only_user' TO 'john'@'%';

Network Restrictions Work

Restrict which IPs can connect to specific accounts:

-- Admin access only from office network
CREATE USER 'admin'@'10.0.1.%' IDENTIFIED BY 'AdminPass123!';

-- App servers from specific subnet
CREATE USER 'app_user'@'192.168.10.%' IDENTIFIED BY 'AppPass456!';

-- Don't do this (allows connections from anywhere):
-- CREATE USER 'user'@'%'

That's it. Basic user management and maybe some roles if you have more than a handful of people. Don't overcomplicate this shit unless compliance specifically requires it.

Encryption: Because Auditors Said So

MySQL Encryption Keys

Most people encrypt MySQL because compliance demands it, not because they give a shit about security. But hey, when your server gets compromised, encrypted data is useless to attackers.

How MySQL Encryption Works

MySQL uses transparent data encryption (TDE) which encrypts your tables automatically. Applications don't need to change, which is nice.

There are two layers - master keys and tablespace keys. Master key encrypts the tablespace keys, tablespace keys encrypt your actual data. Sounds complicated but it means you can rotate the master key without re-encrypting huge tables.

-- Create encrypted table
CREATE TABLE sensitive_data (
  id INT PRIMARY KEY,
  ssn VARCHAR(11),
  email VARCHAR(255)
) ENCRYPTION='Y';

-- Or encrypt existing table (this locks it while running)
ALTER TABLE user_data ENCRYPTION='Y';

Warning: encrypting large existing tables locks them and uses extra disk space. Test on copies first.

Setting Up Encryption Keys

MySQL stores encryption keys in a keyring. Simplest setup is file-based:

## Add to my.cnf
[mysqld]
early-plugin-load=keyring_file.so
keyring_file_data=/var/lib/mysql-keyring/keyring

Create the keyring directory and make sure MySQL can read it:

mkdir /var/lib/mysql-keyring
chown mysql:mysql /var/lib/mysql-keyring
chmod 750 /var/lib/mysql-keyring

Get the permissions wrong and MySQL won't start. Ask me how I know.

Don't Forget Binary Logs

Binary logs contain every data change. Encrypt them too:

-- Enable binary log encryption (requires restart)
SET PERSIST binlog_encryption = ON;
-- Restart MySQL
-- Force rotation to encrypt existing logs
FLUSH BINARY LOGS;

Backup Encryption

Encrypt your backups or encrypted databases are pointless:

## mysqldump with encryption
mysqldump database_name | \\
  openssl enc -aes-256-cbc -salt -k \"BackupPassword123!\" > backup.sql.enc

## Restore
openssl enc -aes-256-cbc -d -salt -k \"BackupPassword123!\" \\
  -in backup.sql.enc | mysql database_name

Test restoring encrypted backups before you need them. Found out the hard way that I'd been using the wrong password for six months of backups.

SSL Connections

Force SSL connections for sensitive data:

-- Require SSL for specific users
CREATE USER 'sensitive_app'@'%'
  IDENTIFIED BY 'SecurePass123!'
  REQUIRE SSL;

-- Or force SSL for all connections
SET PERSIST require_secure_transport=ON;

MySQL generates SSL certificates automatically, which usually work fine unless you need specific certificate attributes.

That's encryption. Enable TDE for sensitive tables, encrypt your backups, force SSL. Done. Don't overthink this unless compliance specifically demands some exotic feature.

Common MySQL Security Questions

Q

Is MySQL actually secure or just marketing bullshit?

A

Default My

SQL is a joke

  • root with no password, anonymous users, test databases anyone can access. But fix those basics and it's solid enough for production. I've run it for years without getting breached.
Q

What should I do immediately after installing MySQL?

A

Run mysql_secure_installation first. It's basic but fixes the worst problems. Then:

  1. Change all default passwords
  2. Delete anonymous users
  3. Remove the test database
  4. Don't bind to 0.0.0.0
  5. Consider forcing SSL connections
mysql_secure_installation
## Follow the prompts - say yes to most things
Q

What are the most common MySQL security mistakes?

A
  1. Default passwords - Especially root with no password
  2. Too many privileges - Giving app accounts ALL PRIVILEGES instead of what they need
  3. Binding to 0.0.0.0 - Exposing MySQL to the internet accidentally
  4. Keeping the test database - With anonymous access that anyone can use
  5. Old accounts - Former employees and contractors still have access
Q

Should I pay for Enterprise or stick with Community?

A

Community handles real security just fine. Enterprise is mostly compliance checkbox bullshit - audit logging and data masking that auditors love to see.

Get Enterprise if compliance specifically demands it. Otherwise you're just paying Oracle for features you don't need.

Q

How do I encrypt data without breaking everything?

A

Small tables: ALTER TABLE tablename ENCRYPTION='Y'; works but locks the table.

Large tables: You'll probably need downtime or a more complex migration process. I usually create encrypted replicas and failover.

Haven't done this enough times to give you a perfect playbook - depends on your setup.

Q

What's the difference between caching_sha2_password and mysql_native_password?

A

caching_sha2_password is more secure but breaks older applications. mysql_native_password is weaker but compatible with everything.

If you're getting authentication errors after upgrading MySQL, it's probably this. Either update your application's MySQL driver or temporarily switch the user back to mysql_native_password.

Q

How do I monitor for security issues?

A

Basic monitoring:

  • Check MySQL error logs for failed login attempts
  • Monitor who's connected: SHOW PROCESSLIST
  • Look for unusual query patterns

I use Percona Monitoring and Management (PMM) for more detailed monitoring, but the built-in Performance Schema tables work too if you don't want to install additional tools.

Q

Is MySQL safe in containers or am I asking for trouble?

A

It's fine if you're not lazy about configuration. Don't run as root, use secrets for passwords (not environment variables), and don't expose it to the world.

I've run MySQL in Docker and Kubernetes for years. Just fix the defaults before you deploy.

Related Tools & Recommendations

compare
Recommended

PostgreSQL vs MySQL vs MariaDB vs SQLite vs CockroachDB - Pick the Database That Won't Ruin Your Life

alternative to mariadb

mariadb
/compare/postgresql-mysql-mariadb-sqlite-cockroachdb/database-decision-guide
100%
compare
Similar content

PostgreSQL vs MySQL vs MariaDB - Developer Ecosystem Analysis 2025

PostgreSQL, MySQL, or MariaDB: Choose Your Database Nightmare Wisely

PostgreSQL
/compare/postgresql/mysql/mariadb/developer-ecosystem-analysis
77%
tool
Recommended

MariaDB Performance Optimization - Making It Not Suck

alternative to MariaDB

MariaDB
/tool/mariadb/performance-optimization
55%
troubleshoot
Recommended

PostgreSQL Breaks in Creative Ways - Here's How to Fix the Disasters

The most common production-killing errors and how to fix them without losing your sanity

PostgreSQL
/troubleshoot/postgresql-performance/common-errors-solutions
35%
tool
Recommended

PostgreSQL - The Database You Use When MySQL Isn't Enough

competes with PostgreSQL

PostgreSQL
/tool/postgresql/overview
35%
tool
Recommended

PostgreSQL - MySQL로 충분하지 않을 때 쓰는 진짜 데이터베이스

competes with PostgreSQL

PostgreSQL
/ko:tool/postgresql/overview
35%
integration
Recommended

Stripe WooCommerce Integration - Doesn't Completely Suck (Unlike PayPal)

Connect Stripe to WooCommerce without losing your sanity or your customers' money

Stripe
/integration/stripe-woocommerce-wordpress/overview
35%
tool
Recommended

WordPress - Runs 43% of the Web Because It Just Works

Free, flexible, and frustrating in equal measure - but it gets the job done

WordPress
/tool/wordpress/overview
35%
tool
Recommended

phpMyAdmin - The MySQL Tool That Won't Die

Every hosting provider throws this at you whether you want it or not

phpMyAdmin
/tool/phpmyadmin/overview
35%
tool
Recommended

MySQL Workbench Performance Issues - Fix the Crashes, Slowdowns, and Memory Hogs

Stop wasting hours on crashes and timeouts - actual solutions for MySQL Workbench's most annoying performance problems

MySQL Workbench
/tool/mysql-workbench/fixing-performance-issues
35%
tool
Recommended

MySQL Workbench - Oracle's Official MySQL GUI (That Eats Your RAM)

Free MySQL desktop app that tries to do everything and mostly succeeds at pissing you off

MySQL Workbench
/tool/mysql-workbench/overview
35%
tool
Recommended

that time mysql workbench almost made sarah quit programming

integrates with MySQL Workbench

MySQL Workbench
/brainrot:tool/mysql-workbench/team-collaboration-nightmare
35%
tool
Recommended

AWS RDS - Amazon's Managed Database Service

integrates with Amazon RDS

Amazon RDS
/tool/aws-rds/overview
35%
tool
Recommended

AWS RDS Blue/Green Deployments - Zero-Downtime Database Updates

integrates with AWS RDS Blue/Green Deployments

AWS RDS Blue/Green Deployments
/tool/aws-rds-blue-green-deployments/overview
35%
tool
Recommended

Google Cloud SQL - Database Hosting That Doesn't Require a DBA

MySQL, PostgreSQL, and SQL Server hosting where Google handles the maintenance bullshit

Google Cloud SQL
/tool/google-cloud-sql/overview
35%
integration
Recommended

Stop Waiting 3 Seconds for Your Django Pages to Load

integrates with Redis

Redis
/integration/redis-django/redis-django-cache-integration
33%
tool
Recommended

Django チーム開発で爆死しない方法

3時に叩き起こされたくない奴のための、現実的な対策

Django
/ja:tool/django/team-development-workflow
33%
compare
Recommended

Django、Flask、FastAPI - 結局どれ使えば死なずに済むのか

integrates with Django

Django
/ja:compare/django/flask/fastapi/production-framework-selection
33%
integration
Recommended

Fix Your Slow-Ass Laravel + MySQL Setup

Stop letting database performance kill your Laravel app - here's how to actually fix it

MySQL
/integration/mysql-laravel/overview
33%
tool
Recommended

SQL Server 2025 - Vector Search Finally Works (Sort Of)

competes with Microsoft SQL Server 2025

Microsoft SQL Server 2025
/tool/microsoft-sql-server-2025/overview
32%

Recommendations combine user behavior, content similarity, research intelligence, and SEO optimization