Three ways to reset a forgotten MySQL root password: start the server with --skip-grant-tables (the classic, works on every version), point the server at an init-file with the new password statement (cleaner, no permission-table tricks), or edit my.cnf for a permanent reset on a controlled box. The exact ALTER USER syntax depends on whether you are on MySQL 5.7, 8.0, or 8.4, and which authentication plugin is in use. I will walk all three, with the version-specific gotchas called out.
The kind of server where this comes up is the one nobody has touched in years: someone provisioned it, set a strong root password, stored it somewhere that no longer exists, and now you have shell access but no mysql credentials. Every method below assumes you have shell access as a user that can stop and start the mysqld process (typically root or whoever owns the data directory). Without that, the recovery options are different and usually involve restoring from a backup.
Jump to:
- Method 1: --skip-grant-tables (all versions)
- Method 2: --init-file (cleaner, no live SQL needed)
- Method 3: my.cnf with mysql_native_password (permanent reset)
- Version compatibility: 5.7, 8.0, 8.4
- Verify and re-lock the server
- FAQ
Method 1: --skip-grant-tables (all versions)
The classic. Tell MySQL to start without loading the privilege tables, log in with no password, change the root password, then restart normally.
# Stop MySQL
sudo systemctl stop mysql # or: sudo service mysql stop
# Start with privilege checks bypassed and no networking
sudo mysqld_safe --skip-grant-tables --skip-networking --socket=:db_socket &
# Connect without a password
mysql -u root --socket=:db_socketOnce you are at the mysql> prompt, set the new password. The exact statement depends on your version:
-- MySQL 8.0 and 8.4
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY ':new_password';
-- MySQL 5.7
UPDATE mysql.user
SET authentication_string = PASSWORD(':new_password')
WHERE User = 'root' AND Host = 'localhost';
FLUSH PRIVILEGES;The FLUSH PRIVILEGES before the ALTER USER is the one most guides skip and the one that bites you on 8.x. Without it, the running server still has the privilege tables in --skip-grant-tables mode and ALTER USER errors out with "The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement". The flush re-enables the privilege subsystem for the rest of your session.
Exit the mysql client, kill the running mysqld_safe process, and start the server normally:
# Kill the recovery instance
sudo pkill -u mysql mysqld
# Start MySQL normally
sudo systemctl start mysql
# Verify the new password works (you will be prompted for :new_password)
mysql -u root -p --socket=:db_socketThis method works on every MySQL version including 5.5, 5.6, 5.7, 8.0, 8.1, 8.2, 8.3, and 8.4. It is also the one that survives the most weird edge cases (corrupted auth plugin, missing socket, mismatched ownership on mysql.sock).
Method 2: --init-file (cleaner, no live SQL needed)
If you prefer not to leave a --skip-grant-tables instance running while you type, write the password change to a file and tell MySQL to execute it at startup.
# Create the init file with the password statement
sudo tee :init_file <<EOF
ALTER USER 'root'@'localhost' IDENTIFIED BY ':new_password';
EOF
sudo chown mysql:mysql :init_file
sudo chmod 600 :init_file
# Start MySQL with the init file
sudo systemctl stop mysql
sudo mysqld --user=mysql --init-file=:init_file &
# Once MySQL is up, stop it and start normally
sudo pkill -u mysql mysqld
sudo systemctl start mysql
# Remove the init file
sudo rm :init_fileThe init-file is read once at server startup and the SQL inside runs with full privileges before any client can connect. It avoids the --skip-grant-tables window where the server is technically running without authentication, which matters on a shared box.
On MySQL 5.7, replace the ALTER USER line with the 5.7 syntax shown in Method 1.
Method 3: my.cnf with mysql_native_password (permanent reset)
When you are setting up a fresh box and want the root password defined in config rather than typed, add it to my.cnf and let it persist across restarts. This is also the workaround for a class of MySQL 8.0+ problems where the default caching_sha2_password plugin fights with old clients.
# /etc/mysql/my.cnf (or /etc/my.cnf on RHEL/CentOS)
[mysqld]
init-file = /etc/mysql/mysql-init.sql
default_authentication_plugin = mysql_native_passwordThen create the init file:
sudo tee /etc/mysql/mysql-init.sql <<EOF
ALTER USER 'root'@'localhost'
IDENTIFIED WITH mysql_native_password BY ':new_password';
EOF
sudo chown mysql:mysql /etc/mysql/mysql-init.sql
sudo chmod 600 /etc/mysql/mysql-init.sql
sudo systemctl restart mysqlNote: mysql_native_password was deprecated in MySQL 8.0 and is no longer the default. In MySQL 8.4 it was removed from the default install entirely and you have to enable it explicitly with --mysql-native-password=ON or by installing the plugin. If you are on 8.4+, prefer caching_sha2_password unless you have legacy clients that cannot speak it.
Version compatibility: 5.7, 8.0, 8.4
| Version | Released | Reset works | Auth-plugin default | Watch out for |
|---|---|---|---|---|
| MySQL 5.5 | 2010 | Method 1 only (5.7 syntax) | mysql_native_password | Use UPDATE mysql.user and PASSWORD() |
| MySQL 5.6 | 2013 | Method 1 (5.7 syntax) | mysql_native_password | Same as 5.5 |
| MySQL 5.7 | 2015 | All methods (5.7 syntax) | mysql_native_password | authentication_string column replaces password |
| MySQL 8.0 | 2018 | All methods (8.0 syntax) | caching_sha2_password | FLUSH PRIVILEGES before ALTER USER |
| MySQL 8.4 | 2024 | All methods (8.0 syntax) | caching_sha2_password | mysql_native_password requires explicit enable |
The most common surprise on a 5.7 → 8.0 upgrade is the syntax shift: 5.7 uses UPDATE mysql.user with PASSWORD(), 8.0+ uses ALTER USER ... IDENTIFIED BY. The two are not interchangeable.
Verify and re-lock the server
After the reset, log in with the new password and confirm both the user and the auth plugin look right:
SELECT User, Host, plugin FROM mysql.user WHERE User = 'root';You should see one row per root user. Each plugin should be either caching_sha2_password (8.0+ default) or mysql_native_password (5.7 and earlier, or by choice). If plugin shows auth_socket, that root account is using socket authentication and cannot be logged into with a password — you would log in as the OS root user instead.
Two final hardening steps for a fresh server:
- Delete the
--init-filefrom disk if you used Method 2 with/tmp/mysql-init.sql. The password is in plaintext inside it. - Run
mysql_secure_installationto remove the test database, disallow remote root login, and remove anonymous accounts.
What to do next
The reset gets you back in; the operational follow-up is locking down what root can do and creating per-application users with the minimum privileges they need. The MySQL Cheat Sheet covers the syntax for CREATE USER, GRANT, REVOKE, and the privilege names you will be choosing from.
If the reason you ended up locked out was a WordPress site whose database password also got lost, the WordPress side has its own reset path: How to Change a WordPress Password (4 Methods) covers the dashboard, WP-CLI, direct database, and email-reset routes for the WP user table.
External reference: the official documentation on resetting the MySQL root password and MySQL 8.4 authentication plugin changes.
FAQ
See also
- Validate Password Strength with Regex: the pattern to enforce length and character-class rules on the new root password before you set it
- How to Change a WordPress Password: the parallel reset flow at the application layer, covering admin dashboard, WP-CLI, direct database, and email reset





