Databases

Reset a Forgotten MySQL Root Password on Linux

Recover access to MySQL or MariaDB on a Linux VPS by starting the server with skip-grant-tables, setting a new root password and restarting normally.

IntermediateLinux server5 min read

To reset a MySQL root password on Linux, stop the database server, start it once with --skip-grant-tables, change the password, then restart it normally. This guide covers the full recovery on Ubuntu, Debian, AlmaLinux and Rocky, for both MySQL 8 and MariaDB, including the checks that stop you from leaving the server wide open.

The method works because --skip-grant-tables tells the server to ignore the privilege tables entirely, so any local user can connect as root without a password. That is also why you must combine it with --skip-networking and finish the job quickly.

Before you start

You need:

  • SSH access to the VPS with a user that can run sudo, or the browser console in your VPS provider's control panel if SSH is unavailable.
  • The name of your database service. On most systems it is mysql; on MariaDB installs it is mariadb.
  • A new root password ready. Use a long random string and store it in your password manager.

Check which engine you are running:

Bash
systemctl status mysql --no-pager
systemctl status mariadb --no-pager

One of the two will report active (running).

Tip: On Debian and Ubuntu, the MySQL and MariaDB root account often uses the auth_socket or unix_socket plugin. That means sudo mysql already logs you in without a password. Try it before doing any recovery:

Bash
sudo mysql -u root -e "SELECT VERSION();"

If that prints a version number, you do not need skip-grant-tables at all. Just set a password for the account:

SQL
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrongPassword!';

Stop the MySQL service

Stop the running server so the recovery instance can take over the socket and data directory.

Bash
sudo systemctl stop mysql

For MariaDB:

Bash
sudo systemctl stop mariadb

Confirm nothing is left running:

Bash
pgrep -a mysqld

An empty result is what you want. If a process is still listed, wait a few seconds and check again.

Start MySQL with skip-grant-tables

Warning: While the server runs with --skip-grant-tables, every local user has full access to every database and no password is checked. Always add --skip-networking so the server only listens on the local socket, and complete the next two steps without leaving the session.

Start the recovery instance in the background:

Bash
sudo mysqld_safe --skip-grant-tables --skip-networking &

Give it a few seconds to open the socket, then connect:

Bash
sudo mysql -u root

You should land on the mysql> prompt with no password prompt.

Note: mysqld_safe is deprecated in newer MySQL releases and may not exist on MySQL 8.4 and later. If you get mysqld_safe: command not found, start the server binary directly instead:

Bash
sudo mysqld --skip-grant-tables --skip-networking --user=mysql &

Reset the MySQL root password

At the mysql> prompt, reload the grant tables first. Without this, MySQL refuses to run account statements while --skip-grant-tables is active.

SQL
FLUSH PRIVILEGES;

Then set the new password:

SQL
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrongPassword!';

If you also have a root@127.0.0.1 or root@::1 account, repeat the statement for each host value you see in SELECT user, host FROM mysql.user;.

On MariaDB 10.3 and older, ALTER USER is not available. Use:

SQL
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('NewStrongPassword!');

Leave the client:

SQL
exit;

Restart MySQL normally

Shut down the recovery instance cleanly:

Bash
sudo mysqladmin shutdown

Then start the service as usual:

Bash
sudo systemctl start mysql

Before you move on, make sure skip-grant-tables was never written into a configuration file:

Bash
grep -r "skip-grant-tables" /etc/mysql/ /etc/my.cnf /etc/my.cnf.d/ 2>/dev/null

No output means the setting only ever existed on the command line, which is correct.

Check it works

Log in with the new password:

Bash
mysql -u root -p -e "SELECT user, host, plugin FROM mysql.user WHERE user='root';"

Enter the password when prompted. You should see the root rows and the authentication plugin in use.

Confirm the server is healthy and listening only where it should be:

Bash
sudo systemctl status mysql --no-pager
sudo ss -tlnp | grep 3306

If port 3306 is bound to 0.0.0.0, decide whether remote access is intended. For a single-server setup, binding to 127.0.0.1 is the safer default.

Troubleshooting

  • ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement — you skipped FLUSH PRIVILEGES;. Run it first, then repeat the ALTER USER statement.
  • Access denied for user 'root'@'localhost' after the restart — the password change was never committed. Stop the service and repeat the recovery, making sure FLUSH PRIVILEGES; runs before the ALTER USER line.
  • mysqld_safe: command not found — your MySQL build dropped the wrapper script. Start mysqld directly with the same flags, or add a temporary systemd drop-in with ExecStart=/usr/sbin/mysqld --skip-grant-tables --skip-networking, then remove it after recovery.
  • Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' — the recovery instance is not running, or it uses a different socket path. Check the error log at /var/log/mysql/error.log and confirm the socket directory exists and is owned by the mysql user.
  • ERROR 1064 near IDENTIFIED BY on MariaDB — you are on a release older than 10.4. Use the SET PASSWORD... = PASSWORD(...) form instead.
  • The server is reachable on port 3306 during recovery — you forgot --skip-networking. Shut the instance down immediately with sudo mysqladmin shutdown and start again with both flags.

Next steps

Now that you are back in, tighten the account and protect the server around it:

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.