Resetting the root password in MySQL 8.0 / MariaDB 10.4+
If you have forgotten the MySQL root password, recovery requires temporarily starting the server in a mode that skips password checks. The procedure differs slightly between MySQL 8.0 and older versions.
Method 1: --skip-grant-tables (universal)
# 1. Stop MySQL
sudo systemctl stop mysql
# or
sudo systemctl stop mariadb
# 2. Start without privilege checks
sudo mysqld_safe --skip-grant-tables --skip-networking &
# 3. Connect without a password
mysql -u root
# 4. Reset the password
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPassword123!';
# For MariaDB < 10.4:
UPDATE mysql.user SET authentication_string=PASSWORD('NewPassword123!') WHERE User='root';
FLUSH PRIVILEGES;
# 5. Exit and restart
EXIT;
sudo killall mysqld_safe mysqld
sudo systemctl start mysqlMethod 2: init-file (recommended for MySQL 8.0)
# 1. Create a file with the SQL command
cat > /tmp/mysql-reset.sql << 'EOF'
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPassword123!';
EOF
# 2. Stop MySQL
sudo systemctl stop mysql
# 3. Start with init-file
sudo mysqld --init-file=/tmp/mysql-reset.sql --user=mysql &
# 4. Wait for startup, then kill it
sleep 5 && sudo killall mysqld
# 5. Delete the file and restart
rm /tmp/mysql-reset.sql
sudo systemctl start mysql
mysql -u root -pMethod 3: through the operating system (Ubuntu/Debian)
# On Ubuntu, MySQL may use unix_socket authentication
sudo mysql
# If this works without a password, you can change the password:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'NewPass!';
FLUSH PRIVILEGES;Changing the password for a regular user
# If you know the current root password:
mysqladmin -u root -pCurrentPassword password NewPassword123!
# Via SQL:
ALTER USER 'username'@'localhost' IDENTIFIED BY 'NewPassword123!';
FLUSH PRIVILEGES;Errors After Resetting the Password
| Error | Cause | Fix |
|---|---|---|
| ERROR 1045 (28000): Access denied for user 'root'@'localhost' | The new password does not match what is stored in the application config, or the reset did not complete (mysqld was not restarted) | Check the password in .env/config.php, restart mysqld normally after the reset |
| ERROR 1698 (28000): Access denied for user 'root'@'localhost' | On Ubuntu, root is bound to the unix_socket plugin, not to a password — ALTER USER with a password does not apply without specifying the plugin | Use ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'pass'; |
| ERROR 2002 (HY000): Can't connect to local MySQL server through socket | The server is not running after an emergency recovery, or the socket is at a non-default path | Check systemctl status mysql and the socket path in my.cnf |
Why Resetting the Root Password Is a Security Risk If the Server Is Left Open
The --skip-grant-tables mode disables privilege checks entirely for every user, not just root — while the server runs in this mode, anyone who can connect to the socket or port 3306 gets full access with no password. The --skip-networking flag in the example command is mandatory: it keeps port 3306 from being reachable during the reset. If the server is reachable from the internet and the reset is done without --skip-networking, the window between startup and the password change is a time when anyone who knows the port is open can take over the database.
When a Simple Password Reset Will Not Fix the Problem
If access to the server is lost not only for root but also for SSH or the provider's console, none of the three methods can be applied — they all require local access to the file system or the ability to restart the mysqld process as a privileged OS user. Managed database services from cloud providers (RDS, Cloud SQL) usually give no direct file access — the root password is reset through the provider's control panel, not through mysqld_safe.
Verifying Access Is Fully Restored
# Connect with the new password
mysql -u root -p -e "SELECT CURRENT_USER(), VERSION();"
# Make sure no other users are left with no password
mysql -u root -p -e "
SELECT User, Host, authentication_string
FROM mysql.user
WHERE authentication_string = '' OR authentication_string IS NULL;"
# Check that networking is listening normally again (if --skip-networking was used)
SHOW VARIABLES LIKE 'skip_networking';
netstat -tlnp | grep 3306An empty result from the second query means no other users are left with an empty password — worth checking right after recovery, because --skip-grant-tables mode is sometimes used for quick "just in case" access and then forgotten open. Privileges for specific users after recovery are covered in the article on managing MySQL users.