MySQL is one of the most popular open source database management systems in the world. It powers many of the web applications and sites we use every day. However, like any powerful technology, MySQL can be vulnerable if not properly secured. A compromised MySQL server can lead to leaked sensitive data, corrupted databases, and even entire websites or applications being taken offline.
Fortunately, MySQL offers a robust set of security features that, when used properly, can protect your databases from most threats. In this comprehensive guide, we will cover all the major steps you need to take to lock down MySQL and keep your data safe.
1. Use Strong Passwords
The first security step is very basic but crucial – always use strong, complex passwords for your MySQL admin accounts. Avoid simple or easily guessable passwords.
Some tips for creating better MySQL passwords:
- Minimum 12 characters in length
- Mix of uppercase, lowercase, numbers and symbols
- Avoid dictionary words and personal information
- Don’t reuse passwords across multiple accounts
- Consider using a password manager to generate and store passwords
It’s also highly recommended to avoid using the default root account and instead create additional admin accounts with strong passwords.
In addition, don’t run your MySQL server as the root operating system user – create a separate MySQL user account for this purpose.
2. Limit Remote Access
By default, MySQL listens for connections on port 3306 from any host. This can leave your MySQL port open to attack.
A better approach is to only allow connections from trusted hosts that need to access MySQL. Here are some ways to limit remote access:
Bind to Specific IP Addresses
In your MySQL config file (my.cnf), specify bind-address directives to restrict listening to one or more IP addresses on your private network:
bind-address=192.168.1.101
bind-address=127.0.0.1
This will make MySQL only listen on the defined IP addresses.
Allow Access Only via VPN
If your remote clients connect via VPN, you can configure MySQL to only allow connections from the VPN tunnel IP subnet.
Use Firewalls
Firewall rules provide another layer of control over remote access. With iptables on Linux, for example, you can only allow connections from specified IP addresses.
The key is to limit connections to only trusted client IPs that genuinely need MySQL access.
3. Use Secure Connections
By default, MySQL transmits data insecurely in plain text. To encrypt connections, you should enable Transport Layer Security (TLS).
There are a few ways to implement TLS:
Enforce TLS for Specific Users
In MySQL, grant permission to a user account to connect via TLS:
mysql> GRANT USAGE ON *.* TO 'mysqluser'@'192.168.1.101' REQUIRE SSL;
This requires the specified user to connect using TLS encryption.
Enable TLS on MySQL Server
To make TLS mandatory for the entire MySQL server, edit your MySQL config:
[mysqld]
ssl-ca=/path/to/ca.pem
ssl-cert=/path/to/server-cert.pem
ssl-key=/path/to/server-key.pem
require_secure_transport=ON
Restart MySQL, and all client connections will now use TLS.
Use SSH Tunneling
Another option is to tunnel your MySQL connection through SSH, which encrypts all traffic. For example:
$ ssh -L 3307:127.0.0.1:3306 [email protected] -N -f
You can then connect locally to the tunnel on port 3307.
4. Improve Authentication Security
Using passwords alone for MySQL auth has some weaknesses. Additional authentication plugins can further lock down access:
Require Two-Factor Authentication
Activate the MFA plugin for accounts:
mysql> CREATE USER 'jeffrey'@'192.168.1.101' IDENTIFIED WITH authentication_ldap_simple
AS 'secretPassword';
mysql> ALTER USER 'jeffrey'@'192.168.1.101'
REQUIRE TWO_FACTOR AUTHENTICATION
VIA one_time_password;
Now logging in will require both a password and one-time code.
Use LDAP Authentication
With the AUTHENTICATION_LDAP_SIMPLE plugin, MySQL can authenticate users externally against an LDAP directory.
Utilize SSH Certificates
The AUTHENTICATION_LDAP_SIMPLE plugin allows verifying clients via SSH certificates rather than passwords.
Restrict Number of Login Attempts
Use the FAILED_LOGIN_ATTEMPTS plugin to lock an account after a specified number failed logins, hindering brute force attacks.
Require Strong Passwords
The VALIDATE_PASSWORD plugin can enforce requirements like password length, complexity, expiration, and history.
5. Implement Role-Based Access Control
MySQL includes a robust permissions system. Rather than granting global privileges, you should implement role-based access control (RBAC) for more granular control.
For example, administrative tasks can be separated into roles like:
- Database administrator –
CREATE
,ALTER
,DROP
,BACKUP
- Application developer –
SELECT
,INSERT
,UPDATE
- Read-only analyst –
SELECT
Give each user the minimum set of privileges needed for their role. Revoke any unneeded permissions.
Also consider row-level or column-level access control for limiting data visibility.
6. Monitor and Audit Activity
To detect unauthorized activity, MySQL provides auditing plugins that can log query executions, data modifications, and admin actions.
Key plugins include:
General Query Log
The General Query Log records all SQL statements executed by MySQL. To enable it, set the general_log
variable to 1 in your MySQL configuration file (my.cnf) or by running the command:
mysql> SET GLOBAL general_log = 'ON';
You can specify the log file location using general_log_file
.
Slow Query Log
The Slow Query Log tracks queries that exceed a defined execution time threshold. To enable it, set the slow_query_log
variable to 1 and define the threshold via long_query_time
(e.g. 10 seconds). For example:
mysql> SET GLOBAL slow_query_log = 'ON';
mysql> SET GLOBAL long_query_time = 10;
The log file location is controlled by slow_query_log_file
.
Binary Log
The Binary Log contains SQL statements that modify data. It is enabled by default in MySQL 5.1+ (for replication purposes). To explicitly enable it, set:
mysql> SET GLOBAL log_bin = ON;
The binary logging format is set via binlog_format
, and the file location is binlog_file
.
Rotate and backup these logs periodically to avoid disk space issues. The logs provide an audit trail of database activity.
7. Apply the Latest Security Patches
Like any software, MySQL releases periodic security patches and version updates. To reduce vulnerabilities, always apply the latest stable MySQL version or patches as soon as possible.
Check the MySQL blog or release notes for security announcements. Major versions like MySQL 8 may receive backports of fixes for older releases like MySQL 5.7.
For Debian/Ubuntu systems, run:
$ sudo apt update
$ sudo apt upgrade mysql-server
On RHEL/CentOS use:
$ sudo yum update mysql-server
8. Avoid Exposing MySQL to Web Frontends
Never directly expose your MySQL server to the public internet. If web applications need to connect to MySQL, consider using a middleware proxy layer like Envoy or HAProxy to add a firewall and control access.
This proxy server can provide:
- Firewall to restrict connections
- Connection pooling to optimize performance
- Query analysis for security monitoring
- Caching to reduce load on database
- Rate limiting to prevent excessive traffic
The proxy adds overhead, but gives you more control than directly exposing MySQL.
9. Take Advantage of User Permissions
As mentioned earlier, align MySQL user permissions with the principle of least privilege. Give each user only the capabilities needed for their work.
But user permissions can provide another layer of security beyond just data access:
Restrict Process Privileges
The PROCESS
and SUPER
privileges allow modifying MySQL server settings and processes. Limit users who absolutely require these.
Limit User Resources
The MAX_USER_CONNECTIONS
resource limit prevents any one user from opening too many connections that could overload MySQL.
Restrict User Account Locking
Enable the CREATE USER
or ALTER USER
privileges to restrict users that can lock/unlock other accounts, preventing unauthorized changes.
Limit Users that Can Create New Users
Be cautious about granting the CREATE USER
privilege since new user creation could open security holes.
10. Take Advantage of Database Privileges
Similar to user accounts, you can apply the principle of least privilege at the database level:
Limit CREATE/ALTER Database Privileges
Be careful about allowing users to create or modify the structure of databases.
Restrict DROP Database Privileges
The DROP
privilege at the database level can be dangerous – limit users that have this capability.
Assign Database Roles
Roles like db_datareader
or db_datawriter
can define pre-configured privilege sets on a database, implementing database-level RBAC.
11. Secure Your MySQL Files and Directories
The filesystem holding your MySQL data directories, tablespaces, and log files should be locked down:
Restrict File Permissions
Never allow global read/write access to MySQL files. Revoke unnecessary permissions to keep access limited.
Enable Secure File Transfer
Consider using SFTP or SSH for secure file transfer rather than insecure FTP.
Separate Database and Log Files
Put MySQL database directories and log files on different disk volumes. This adds resilience if one disk volume fails or fills up.
Encrypt Database Files
Tools like MySQL Enterprise Edition’s Transparent Data Encryption can encrypt database files, protecting against unauthorized access.
12. Take Care When Using Replication
MySQL replication allows you to maintain identical slave databases. This powerful capability also introduces security considerations:
Use TLS for Replication Traffic
Just as you encrypt client connections, also use TLS to encrypt replication data transfer between master and slave.
Restrict Replication Privileges
Grant the REPLICATION SLAVE
privilege with care, only to accounts that require it. Also consider using role-based access control.
Monitor the Binary Log
Check the binary log regularly for any potentially malicious SQL during replication.
13. Perform Regular Backups
Backups provide an important defense against catastrophic data loss due to hardware failure, data corruption, accidental deletes, and even ransomware attacks.
Consider combining:
- Full daily or weekly backups
- More frequent incremental backups
- Transaction log backups
Test restores regularly to verify your backups are working properly. Encrypt your backups, and store them in multiple secured locations.
14. Take Advantage of MySQL 8 Security Features
If possible, upgrade to the latest MySQL major version 8.x to take advantage of improved security:
Better Password Protection
MySQL 8 has better password hashing via caching_sha2_password
and stronger validation with expired password checking.
Role-Based Access Control
More advanced RBAC capabilities for administrative privileges and data access.
Default Authentication Plugin
New installs will have the strong caching_sha2_password
plugin enabled by default.
Improved Encryption
MySQL 8 adds support for encrypted undo logs, redo logs, and data file pages.
Conclusion
Securing a MySQL database server takes diligence, but the peace of mind is worth the effort. Use the comprehensive tips provided in this guide as a blueprint to lock down your MySQL environments. Always keep security top of mind when setting up new instances.
By leveraging MySQL’s robust access control, encryption, auditing and more, you can deploy database infrastructure with confidence your data is protected from most attacks. Combine these database-level measures with system-level protections like firewalls, security groups and VPNs to implement defense in depth.
While no security regimen eliminates all risk, providing multiple layers of security makes the barrier to compromise increasingly high. With proper implementation of MySQL security along with vigilant monitoring and maintenance, you can avoid the vast majority of database threats.