MySQL Secure Installation and Password Validation
The four things `mysql_secure_installation` is famous for are already done on Ubuntu - the transcript shows no anonymous users, no test database and root bound to localhost. What is missing is password validation, which is a component you install yourself.
Foundations Guide 2 of 45 Beginner
- OSUbuntu 26.04 LTS (resolute)
- MySQL8.4.10-0ubuntu0.26.04.1
- Packagemysql-server (Ubuntu archive)
- TimeAbout 15 min
- Reviewed27 August 2026
Written against the versions above. Ubuntu's packaging does most of this at install time. On a tarball or Oracle APT install the same checks are worth running, and they will find work to do.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| db-a01 | 192.168.0.81 | Ubuntu 26.04 LTS | Primary / Source / Replica Set Member 1 | 2 Core | 4 GB | 50 GB |
Before you start
- MySQL installed and running - see the installation guide in this track.
sudoaccess, which is how you reach root while it is onauth_socket.
-
Look for anonymous accounts
The first thing the script removes. An anonymous account has an empty user name and lets anyone who can reach the server connect without identifying themselves.
The result is empty - not a table with no rows, but no output at all, which is what
--tableprints when nothing matches. Ubuntu's package does not create them.bash sudo mysql --table -e "SELECT user, host FROM mysql.user WHERE user = ''"Expected resultNo rows. There are no anonymous accounts to remove.
Success conditionYou have confirmed the first hardening step is already done.
-
Look for the test database
The second thing the script removes: a database called
testthat any account could write to, plus themysql.dbgrants that made that possible.SHOW DATABASESlists four, and every one is a system schema -information_schema,mysql,performance_schemaandsys. Notest. Themysql.dbtable then shows only two rows, both internal accounts being granted their own schemas.Two of the four classic steps, and neither has anything to do.
bash Example session sudo mysql -e "SHOW DATABASES"Databaseinformation_schemamysqlperformance_schemasyssudo mysql --table -e "SELECT Host, Db, User FROM mysql.db"+-----------+--------------------+---------------+| Host | Db | User |+-----------+--------------------+---------------+| localhost | performance_schema | mysql.session || localhost | sys | mysql.sys |+-----------+--------------------+---------------+Expected resultFour system databases, no
test, and two internal rows inmysql.db.Success conditionYou have confirmed there is no test database and no loose grant on one.
-
Check whether root can reach the server from anywhere else
The third step: disallowing remote root login.
rootexists once, with hostlocalhost. The host column is part of the account identity in MySQL -root@localhostandroot@%would be two different accounts with different passwords. There is no second root here, so there is no remote root to disable.bash Example session sudo mysql --table -e "SELECT user, host FROM mysql.user WHERE user = 'root'"+------+-----------+| user | host |+------+-----------+| root | localhost |+------+-----------+Expected resultOne row:
rootatlocalhost.Success conditionYou know root cannot be used from another machine.
-
Find the step that IS missing
Password validation is a loadable component, and
mysql.componentis the table that records which components are installed.It comes back empty. Nothing is enforcing password quality, so any account you create can have any password you like - including
abc.This is the one part of the traditional hardening pass that Ubuntu leaves to you.
bash sudo mysql --table -e "SELECT component_urn FROM mysql.component"Expected resultNo rows. No components are installed.
Success conditionYou have found the gap the packaging does not close.
-
Install the validation component and read the policy it applies
INSTALL COMPONENTis persistent - the component is recorded inmysql.componentand loads again on every restart. There is nothing to add to a config file.The variables it registers are the policy. At MEDIUM, the default, a password must be at least 8 characters and contain at least one uppercase, one lowercase, one digit and one special character.
check_user_namebeingONalso blocks a password that matches the account name.bash Example session sudo mysql -e "INSTALL COMPONENT 'file://component_validate_password'"sudo mysql --table -e "SHOW VARIABLES LIKE 'validate_password%'"+-------------------------------------------------+--------+| Variable_name | Value |+-------------------------------------------------+--------+| validate_password.changed_characters_percentage | 0 || validate_password.check_user_name | ON || validate_password.dictionary_file | || validate_password.length | 8 || validate_password.mixed_case_count | 1 || validate_password.number_count | 1 || validate_password.policy | MEDIUM || validate_password.special_char_count | 1 |+-------------------------------------------------+--------+Expected resultThe install returns nothing, then eight
validate_password.*variables withpolicyset toMEDIUMandlengthto 8.Success conditionPassword validation is active and you can see exactly what it demands.
-
Prove it rejects a weak password
The fastest way to confirm a policy is loaded is to violate it.
ERROR 1819and exit status 1. The account is not created - this is a refusal, not a warning. Note that the error names the policy rather than the specific rule broken;abcfails length, case, digit and special-character checks all at once.bash Example session sudo mysql -e "CREATE USER 'weakling'@'localhost' IDENTIFIED BY 'abc'" ; echo "exit=$?"ERROR 1819 (HY000) at line 1: Your password does not satisfy the current policy requirementsexit=1Expected result
ERROR 1819 (HY000): Your password does not satisfy the current policy requirementsandexit=1.Success conditionYou have seen the policy refuse a real attempt.
-
Create an account that satisfies it
The same statement with a password that meets all four requirements.
exit=0and no output, which is SQL for success.Look at the
plugincolumn in the account list afterwards.appuseris oncaching_sha2_password, the 8.x default for password accounts - notauth_socketlike root. This account has a real password and can therefore be used over the network, which root cannot.That difference is the subject of the connections guide later in this track.
bash Example session sudo mysql -e "CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'S7rong-Pass!2026'" ; echo "exit=$?"exit=0sudo mysql --table -e "SELECT user, host, plugin FROM mysql.user ORDER BY user"+------------------+-----------+-----------------------+| user | host | plugin |+------------------+-----------+-----------------------+| appuser | localhost | caching_sha2_password || debian-sys-maint | localhost | auth_socket || mysql.infoschema | localhost | caching_sha2_password || mysql.session | localhost | caching_sha2_password || mysql.sys | localhost | caching_sha2_password || root | localhost | auth_socket |+------------------+-----------+-----------------------+Expected result
exit=0, then six accounts withappuseroncaching_sha2_password.Success conditionYou have one working password account and know which plugin it uses.
Troubleshooting
ERROR 1819on a password you believe is strong.Why: MEDIUM policy checks four separate things, and
check_user_nameadds a fifth - a password containing the account name is refused however complex it is.Fix:Read
SHOW VARIABLES LIKE 'validate_password%'and satisfy each line. Do not lower the policy to get past one account.The component installs, but passwords are still accepted after a restart.
Why: Almost always a second server, or a config file loading a different data directory.
mysql.componentis per data directory.Fix:
SELECT component_urn FROM mysql.componenton the server you are actually connected to, thenSELECT @@datadirto confirm which one that is.You want the four classic checks anyway on a non-Ubuntu install.
Why: Tarball and Oracle APT installs do create anonymous accounts and the test database.
Fix:Run
mysql_secure_installation. On this platform it will find nothing to do, which is what the first three steps here proved.
Official sources
- MySQL 8.4 Reference Manual - mysql_secure_installation
- MySQL 8.4 Reference Manual - The Password Validation Component
- MySQL 8.4 Reference Manual - mysql, the MySQL Command-Line Client
- MySQL 8.4 Reference Manual - Connecting to the MySQL Server
- MySQL 8.4 Reference Manual - Server System Variables (bind_address)