
Database misconfigurations are among the most common causes of data breaches — and most of them are preventable. The majority of MySQL security improvements are straightforward, do not require specialized security expertise, and take a matter of hours to implement.
This checklist covers the essentials. Work through it on every MySQL instance you manage.


MySQL installs with defaults intended for initial setup convenience, not production security.
DELETE FROM mysql.user WHERE User = ”;
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db = ‘test’ OR Db = ‘test\\_%’;
FLUSH PRIVILEGES;
These defaults represent unnecessary attack surface. Remove them from every production instanc
mysql_secure_installation
This guided utility covers root password, anonymous user removal, remote root login, and the test database. Run it on every new instance. Then continue through the rest of this checklist — it does not cover everything.
Verify root accounts:
SELECT User, Host FROM mysql.user WHERE User = ‘root’;
Remove any root entry not restricted to localhost:
DELETE FROM mysql.user
WHERE User = ‘root’
AND Host NOT IN (‘localhost’, ‘127.0.0.1’, ‘::1’);
FLUSH PRIVILEGES;
Root access belongs on the server itself, through a secure session — not from a remote client.
Every application gets its own dedicated account with only the permissions it actually needs.
CREATE USER ‘app_user’@’10.0.1.50’ IDENTIFIED BY ‘strong_password’;
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.*
TO ‘app_user’@’10.0.1.50’;
FLUSH PRIVILEGES;

Audit user accounts quarterly and revoke anything no longer needed.
Specifying the host when creating users limits where that user can connect from.

‘user’@’%’ is convenient in development. It should not exist in production.
MySQL 8.0 defaults to caching_sha2_password , which is stronger than the older mysql_native_password . If older accounts still use the legacy plugin, upgrade them:
ALTER USER ‘app_user’@’host’
IDENTIFIED WITH caching_sha2_password BY ‘new_strong_password’;
Enforce strong passwords and rotate them on a defined schedule. For high-security environments, certificate-based authentication removes passwords from the equation entirely.
Without SSL/TLS, credentials and query data travel in plaintext across your network.
— Check SSL status
SHOW VARIABLES LIKE ‘%ssl%’;
— Require SSL for a specific user
ALTER USER ‘app_user’@’host’ REQUIRE SSL;
To enforce SSL for all connections, add to my.cnf :
If the application and database are on the same server, restrict MySQL to localhost:
[mysqld]
bind-address = 127.0.0.1
If MySQL must be remotely accessible, use a firewall to restrict which IP addresses can reach port 3306. Host-based user restrictions in MySQL are a second layer of defense — not a substitute for network-level controls.
Audit logs record who connected, from where, and what SQL they ran. Required for compliance (PCI-DSS, HIPAA, SOC 2) and invaluable for incident investigation.
— Check if audit logging is active
SHOW PLUGINS LIKE ‘%audit%’;
At minimum, log all connection attempts, all DDL statements (CREATE, ALTER, DROP), and failed authentication. Failed auth attempts should trigger real-time alerts.
Check your current version:

Subscribe to MySQL security advisories and plan patch windows before vulnerabilities are public.
Encrypt sensitive tables at the InnoDB level:
— New table with encryption
CREATE TABLE sensitive_data (
id INT,
ssn VARCHAR(11)
) ENCRYPTION = ‘Y’;
— Encrypt an existing table
ALTER TABLE sensitive_data ENCRYPTION = ‘Y’;
Pair InnoDB encryption with full-disk encryption (LUKS on Linux, BitLocker on Windows) for defense in depth.
Security is not a one-time configuration. It is ongoing monitoring.

MONyog monitors connection patterns, authentication failures, and anomalous query activity continuously — alerting you when something looks wrong rather than after damage is done.

Want continuous security monitoring for your MySQL databases? Try MONyog free and configure alerts for anomalies that matter most to your environment.
Three things that take under an hour: (1) verify root cannot log in remotely; (2) replace any ‘user’@’%’ accounts with specific IP bindings; (3) audit all user accounts and revoke permissions that are no longer needed. These eliminate the most common attack vectors in production MySQL environments
Yes. Private networks are not inherently secure — misconfigured firewalls, insider threats,
and compromised internal systems are all real. TLS adds minimal overhead and is a common compliance requirement regardless of network topology.
Every 90 days for production accounts, and immediately after any team member with database access leaves. Using a secrets manager for automated rotation removes this from the manual checklist and eliminates the risk of rotation being skipped.
PCI-DSS (payment card data), HIPAA (health information), SOC 2 (service organizations), and GDPR (personal data of EU residents) all have database security requirements. Specific controls vary, but generally include access controls, encryption in transit and at rest, audit logging, and regular patching.
From a security standpoint, co-location reduces attack surface (no network path between app and database) but means a compromise of the application server also compromises the database. For production workloads, separate servers with a strict firewall rule on port 3306 is the recommended pattern.
Run through the CIS MySQL Benchmark — the Center for Internet Security publishes free, detailed hardening guides for MySQL that are widely referenced in compliance audits. These guides give you a point-by-point checklist with specific commands to verify each item.
Changing the port reduces automated scanner noise slightly, but it is not a meaningful security control. A firewall that blocks port 3306 from all sources except your application servers is far more effective and does not add the operational complexity of a non-standard port.
Audit logs can grow significantly on busy servers. Set up log rotation, monitor disk space on the audit log destination, and configure MONyog to alert when space falls below a safe threshold. On some MySQL configurations, a full audit log partition can cause MySQL to pause writes — plan storage capacity accordingly.