MySQL ships with several default settings and accounts that must be hardened before the server handles production data. On RHEL 8, the combination of mysql_secure_installation, strict privilege grants, TLS enforcement, and the audit log plugin provides a strong baseline. This tutorial walks through each layer of MySQL security so that nothing is left at its insecure default. By the end you will have a locked-down MySQL 8.0 instance ready for application use.

Prerequisites

  • RHEL 8 server with a non-root sudo user
  • MySQL 8.0 installed and the mysqld service running
  • The temporary root password from /var/log/mysqld.log (first-time installs)
  • Basic familiarity with the MySQL CLI

Step 1 — Run mysql_secure_installation

mysql_secure_installation is an interactive script that guides you through the most critical hardening steps. Run it immediately after installation and accept the prompts to set a strong root password, remove anonymous users, disable remote root login, and drop the test database.

sudo mysql_secure_installation

When prompted, enable the VALIDATE PASSWORD component and choose strength level 2 (STRONG) to enforce passwords of at least eight characters containing uppercase, lowercase, digits, and special characters. Answer Y to every subsequent question.

Step 2 — Remove Anonymous Users and Disable Remote Root Login

If you skipped the interactive script or want to verify manually, connect as root and run the following SQL statements. Anonymous users allow anyone on the localhost to connect without credentials, which is never acceptable in production.

mysql -u root -p

-- Remove any remaining anonymous accounts
DROP USER IF EXISTS ''@'localhost';
DROP USER IF EXISTS ''@'127.0.0.1';

-- Ensure root cannot log in remotely
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');

FLUSH PRIVILEGES;

Step 3 — Enforce TLS with require_secure_transport

MySQL 8.0 auto-generates self-signed TLS certificates on first start. To force every connection to use TLS, add the require_secure_transport option to the server configuration and restart the service. Edit /etc/my.cnf.d/mysql-server.cnf under the [mysqld] section.

sudo tee -a /etc/my.cnf.d/mysql-server.cnf <<'EOF'
[mysqld]
require_secure_transport = ON
EOF

sudo systemctl restart mysqld

Verify TLS is active by checking the status variable after reconnecting:

mysql -u root -p -e "SHOW VARIABLES LIKE 'require_secure_transport';"

Step 4 — Create a Least-Privilege Application User

Application accounts should never use the root user. Create a dedicated account and grant only the specific privileges the application requires on its own database. This limits the blast radius of a compromised application credential.

mysql -u root -p <<'SQL'
CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'Str0ng!Passw0rd';

-- Grant only what is needed — no SUPER, no FILE, no GRANT OPTION
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'appuser'@'localhost';

FLUSH PRIVILEGES;
SQL

Step 5 — Install and Enable the Audit Log Plugin

The MySQL Enterprise Audit plugin (available in community builds as audit_log) writes a tamper-evident log of all connection and query activity. Load it at runtime and configure it to use JSON format for easy ingestion into log aggregators.

mysql -u root -p <<'SQL'
INSTALL PLUGIN audit_log SONAME 'audit_log.so';

SET GLOBAL audit_log_format = 'JSON';
SET GLOBAL audit_log_policy = 'ALL';
SQL

# Persist settings across restarts
sudo tee -a /etc/my.cnf.d/mysql-server.cnf <<'EOF'
plugin-load-add = audit_log.so
audit_log_format = JSON
audit_log_policy = ALL
EOF

Step 6 — Configure mysql_config_editor for Passwordless Scripts

Storing database passwords in shell scripts or cron jobs in plain text is a common security mistake. The mysql_config_editor utility encrypts credentials into ~/.mylogin.cnf so that scripts can connect without exposing the password in the process list or shell history.

# Store credentials under the alias 'appuser'
mysql_config_editor set --login-path=appuser 
  --host=localhost 
  --user=appuser 
  --password

# Use the stored credentials in a script
mysql --login-path=appuser appdb -e "SELECT COUNT(*) FROM orders;"

The --login-path flag replaces the -u, -p, and -h flags. The encrypted file is readable only by the owning OS user, preventing other system users from extracting the password.

Conclusion

You have hardened MySQL 8.0 on RHEL 8 by running the secure installation script, removing anonymous accounts, blocking remote root logins, enforcing TLS transport, creating a least-privilege application user, enabling the audit log plugin, and securing scripted credentials with mysql_config_editor. Each of these controls addresses a distinct attack vector, and together they form a layered defence appropriate for production workloads.

Next steps: How to Configure MySQL Replication on RHEL 8, How to Back Up MySQL with mysqldump and mysqlpump on RHEL 8, and How to Monitor MySQL Performance with Performance Schema on RHEL 8.