Skip to content
DevOps devops databases 6 min read

Securing MySQL

When you first install MySQL (a popular open-source relational database) on a server, it ships with a few insecure defaults that are fine for a quick test but dangerous in the real world: a database account with no password, an anonymous login anyone can use, and a throwaway test database that any user can write to. MySQL bundles a small helper program called mysql_secure_installation that walks you through closing all of these holes in a couple of minutes. Running it is the essential first step after every fresh install, before you create a single real table.

What mysql_secure_installation actually does

mysql_secure_installation is an interactive script (a program that asks you yes/no questions and acts on your answers). It does not do anything you couldn’t do by hand with SQL commands. It just bundles the most important hardening steps into one guided flow so you don’t forget any of them. Specifically it lets you:

  • Set or change the password for the root account (the all-powerful admin user).
  • Turn on the validate_password component (rules that reject weak passwords).
  • Remove anonymous users (accounts with a blank username that anyone can log in as).
  • Disallow root from logging in remotely (over the network).
  • Drop the test database that ships with MySQL.
  • Reload the privilege tables so all of the above takes effect immediately.

When to run it: every single time, right after apt install mysql-server, on every environment from your laptop to production. There is no good reason to skip it.

Understanding root auth on Ubuntu: auth_socket vs password

Before you run the script, you need to understand one Ubuntu-specific quirk. On Ubuntu 22.04 and 24.04 LTS, the MySQL package configures the root account to use the auth_socket plugin instead of a password.

  • auth_socket means MySQL trusts the operating system. If you are already logged into the Linux server as the root system user (or using sudo), MySQL lets you in with no password. If you are any other Linux user, you are refused — even with the correct password. This is actually quite secure for a single-admin box because there is no password to steal or brute-force.
  • password (caching_sha2_password) is the classic model: you supply a username and password, and MySQL checks it. You need this if an application or a person must connect without being the root Linux user.
auth_socketPassword (caching_sha2_password)
How you log insudo mysql (no password)mysql -u root -p then type password
Best forThe local admin on a single serverApp users, remote logins, GUI tools
Password to steal?NoneYes — must be stored/managed
Default for root on UbuntuYesNo

If mysql_secure_installation asks you to set a root password but root is still on auth_socket, the password you set may be ignored at login — you will still log in with sudo mysql. That confuses many beginners. Decide which scheme you want first (see the bottom of this page).

Running the script step by step

First make sure the MySQL service (the background program, also called a daemon) is running, then launch the helper. You must use sudo because it needs admin access.

sudo systemctl status mysql
sudo mysql_secure_installation

Output:

Securing the MySQL server deployment.

Connecting to MySQL using a blank password.

The script now asks a series of questions. Here is each prompt explained.

Prompt 1 — VALIDATE PASSWORD component

VALIDATE PASSWORD COMPONENT can be used to test passwords...
Would you like to setup VALIDATE PASSWORD component? [y/N]

Answer y to enforce password strength rules, then pick a policy level:

There are three levels of password validation policy:
LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary file
Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 1

1 (MEDIUM) is a sensible default for most servers. When NOT to enable this: if your root account stays on auth_socket and you only ever create users through automation that already generates strong passwords, the prompts add friction. Otherwise, leave it on.

Prompt 2 — set the root password

Please set the password for root here.
New password:
Re-enter new password:

Type a strong password (it will not show on screen). On a fresh install with auth_socket, the script may instead just confirm the existing setup. Either way, choose a password you store in a secrets manager.

Prompt 3 — remove anonymous users

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y

Always answer y. Anonymous users let anyone with network access to the database connect without credentials. There is no legitimate production use for them.

Prompt 4 — disallow remote root login

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y

Answer y. This forces anyone wanting root to be physically on the server (via SSH first). Remote root over the network is a prime target for attackers. Create dedicated application users for remote connections instead.

Prompt 5 — drop the test database

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y

Answer y. The test database is world-writable by default and serves no purpose on a real server.

Prompt 6 — reload privilege tables

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
All done!

Answer y so every change above takes effect at once without restarting MySQL.

Switching root from auth_socket to a password (optional)

If you genuinely need root to log in with a password (for example, a desktop GUI tool that cannot run as the Linux root user), do this manually after the script. First log in:

sudo mysql

Then change the auth method:

ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'YourStrongPassword!23';
FLUSH PRIVILEGES;
EXIT;

Verify it worked from a non-root shell:

mysql -u root -p

Output:

Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
mysql>

Best practice on production is to leave root on auth_socket and never give it a password. Instead create a separate admin user with a strong password and only the privileges it needs. That way a leaked password can never touch the root account.

Confirming the lockdown

You can double-check the result with a couple of SQL queries:

sudo mysql -e "SELECT user, host FROM mysql.user;"

Output:

+------------------+-----------+
| user             | host      |
+------------------+-----------+
| debian-sys-maint | localhost |
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+

Notice there are no blank usernames (anonymous users gone) and root is bound only to localhost (no remote root).

Best Practices

  • Run mysql_secure_installation immediately after install, before creating any real databases or users.
  • Keep root on auth_socket and use sudo mysql for admin; create a separate strong-password admin user only if you must.
  • Always remove anonymous users, drop the test database, and disallow remote root — answer y to all three.
  • Pair MySQL hardening with the firewall: by default MySQL listens on 127.0.0.1 only; if you must expose it, restrict port 3306 with ufw to known IPs.
  • Store every database password in a secrets manager, never in plain text or shell history.
  • Re-run the script (or re-check mysql.user) after any major MySQL upgrade to confirm defaults weren’t reintroduced.
Last updated June 15, 2026
Was this helpful?