MySQL security hardening (status audit, network, TLS, authentication, privileges, audit, encryption)
MySQLLevel: IntermediateDuration: 5 min (audit) – 3 hours (full hardening)This is not an installation guide: it finds and closes the gaps of a running MySQL 8.4 / 8.0 server. First the read-only Status audit lists the findings by severity and tells you which card each finding leads to; then you close the areas one by one or all of them in order: bind_address, firewall and host restrictions on accounts; TLS, require_secure_transport and VERIFY_IDENTITY on the client; caching_sha2_password, password policy, remote root and anonymous accounts; roles and an application account without DDL; audit; InnoDB tablespace encryption (keyring component); encrypted backups; operating system; version tracking. Audit is not available in Community: it requires MySQL Enterprise (paid subscription) or Percona Server (free); TDE is available in Community too. At the end the audit runs again.
Topology: Single MySQL server + application server (client verification); replica/InnoDB Cluster in the notes
Scenarios
- Status audit: what are my gaps? (read-only) — The scan to run first: anonymous, passwordless and remote root accounts, access from anywhere (%), weak authentication plugin, global privileges, TLS, audit, encryption, file permissions and firewall; it changes nothing.
- Full hardening (all in order) — Newly installed or never hardened server: all areas are applied in a safe order; MySQL is restarted several times (a maintenance window is required).
- Network and connections: who can connect from where? (bind_address, firewall, host restriction) — MySQL listens on all interfaces, accounts have host '%', the port is open to everyone. Changing bind_address requires a restart.
- Encrypt connections (TLS, require_secure_transport, VERIFY_IDENTITY) — The automatically generated self-signed certificate is in use, unencrypted connections are accepted, or clients do not verify the certificate. No downtime with ALTER INSTANCE RELOAD TLS.
- Authentication and passwords (caching_sha2, password policy, root) — mysql_native_password accounts, no password policy, remote root, anonymous accounts and the test database. No downtime.
- Least privilege: roles and an application account without DDL — CREATE/ALTER/DROP or . privileges on the application account, accounts with FILE/SUPER; read/write/DDL roles and a privilege report. No downtime.
- Audit: who did what? — The auditor wants session and query logging. MySQL Community has no built-in audit: Enterprise Audit, the Percona Server Audit Log Filter, or limited options for Community. License: Enterprise Audit comes only with a MySQL Enterprise subscription; the Percona Audit Log Filter is free.
- Encrypt data at rest (InnoDB tablespace encryption, keyring) — Table, redo, undo and binlog encryption against theft of the disk or a backup copy; one restart to install the keyring component, ALTER time on large tables. It needs no license in Community either; the encrypted/KMS keyrings are Enterprise.
- Backup security (encrypted backups, login-path, permissions) — Backups unencrypted or in a world-readable directory, plain-text password in scripts; mysqldump + GPG or XtraBackup --encrypt, a backup account and login-path.
- Operating system side (service account, permissions, core dump, SELinux) — Data directory or certificate files are open to others, secure_file_priv is empty, local_infile is on, SELinux is disabled. Some settings take effect on restart.
- Patches and versions: am I on a supported version? — Version, end of support (8.0 ended in April 2026) and pending updates; links to the upgrade guide for applying them. Read-only.
Before you start
- MySQL … is running and, as root on the server, the mysql command logs in without a password (root@localhost with auth_socket, or a client login-path set with mysql_config_editor). If the installation was done with the MySQL installation guide, this is already in place. The SQL in the steps runs as root through mysql -t.
- Two separate SSH sessions are open to the server; in one of them the mysql client stays open. After changing account hosts, require_secure_transport and the firewall, test a new connection in a separate session; do not close the old sessions until you see it succeed. The root@localhost socket login never changes in this guide: it always remains as the way back.
- Maintenance window: in the areas you select, MySQL will be restarted (bind_address, keyring component, audit plugin, core dump limit). In an environment with replicas, apply it on the replicas first.
- A list of all applications that connect to MySQL (server IPs, accounts, driver versions). The audit step shows the current connections; a client that is not on the list cannot connect after the restriction.
- A current backup with a tested restore exists (logical or XtraBackup). The encryption (TDE) step makes the data unreadable if the keyring file is lost: take the backup BEFORE the keyring.
Phases of the guide
- Status audit (read-only) — List the findings inside the database · Audit the operating system side
- Before you start: fallback point — Take a copy of the current settings, accounts and privileges · Enable the extra configuration directory
- Privileges — 1. Diagnosis — Show the accounts' privileges
- Privileges — 3. Apply — Create the roles and grant privileges · Create the accounts and attach them to the roles · Remove the application account's direct privileges · Privilege report
- Privileges — 4. Verification — Verify that the effective privileges contain no DDL · DDL attempt from the application server
- Privileges — 5. Afterwards — Keep the migration account locked when it is not in use
- Authentication — 1. Diagnosis — Show the authentication plugins, password settings and default accounts
- Authentication — 2. Safety net — Check driver compatibility
- Authentication — 3. Apply — Remove the anonymous accounts, remote root and the test database · Set up the password policy (validate_password, history) · Move mysql_native_password accounts to caching_sha2_password · Create the personal DBA account
- Authentication — 4. Verification — Verify the account state · Try logging in as root from the application server
- TLS — 1. Diagnosis — Show the current TLS settings and unencrypted clients
- TLS — 3. Apply — Create a test CA and a server certificate · Create the key and the certificate signing request (CSR) · Put the signed certificate in place · Verify the certificate and the key · Set the SELinux label · Switch the server to the new certificate (no downtime) …
- TLS — 4. Verification — Verify that unencrypted connections are rejected
- TLS — 5. Afterwards: certificate renewal — Certificate renewal procedure
- Network — 1. Diagnosis: who connects from where? — Show the listen address, account hosts and active clients
- Network — 3. Apply — Restrict accounts with host '%' to the application network · Restrict the listen address (takes effect at restart) · Open the port in the firewall only to the allowed networks · Restart MySQL for the listen address
- Network — 4. Verification — Test a connection from the application server (new session)
- Audit — 1. Diagnosis — Show the audit plugins and log settings
- Audit — 3. Apply — Community: log failed logins and the DML statement text · Install the Enterprise Audit plugin · Define the Enterprise Audit filters · Install the Percona Audit Log Filter component · Define the Percona audit filters · Forward the audit log to the central server (rsyslog imfile) …
- Audit — 4. Verification — Make a change and see its trail
- Backup — 1. Diagnosis — Show the encryption state of the backups and the password files
- Backup — 3. Apply — Create the backup account with least privilege · Save the password in a login-path · Import the GPG public key · Encrypted backup script · Encrypted backup script with XtraBackup · Key file, backup directory and manual test …
- Backup — 4. Verification — Test that the encrypted backup can be decrypted
- Operating system — 1. Diagnosis — Service account, permissions, file privileges and SELinux
- Operating system — 3. Apply — Restrict file import/export · Fix the data directory and key file permissions · Disable core dumps · Reload systemd and restart MySQL · Keep passwords out of the command history · Keep SELinux in Enforcing mode
- Operating system — 4. Verification — Verify the changes
- Encryption — 1. Diagnosis — Show the keyring and encryption state
- Encryption — 2. Safety net — Full backup before encryption
- Encryption — 3. Apply — Write the keyring component manifest · Prepare the keyring directory and configuration · Restart to load the keyring · Enable encryption for redo, undo, binlog and new tables · Encrypt the tables of the application database · Back up the keyring file
- Encryption — 4. Verification — Verify the encryption and the keyring