Locked out of MySQL as root is one of those problems that feels bigger than it is. You've forgotten the password, someone changed it and left, or a fresh restore left you with credentials that no longer match — and now every mysql -u root -p attempt just throws back ERROR 1045 (28000): Access denied for user 'root'@'localhost'. If you're on a self-managed VPS running MySQL or MariaDB directly (not through cPanel, which handles this differently), here's how to get back in without reinstalling anything.

Symptom

You SSH into your VPS, try to log into MySQL as root, and get denied. Sometimes it's a password you're sure is right. Sometimes it's a server you inherited and nobody documented the credentials. Either way, WordPress sites on the box are probably already throwing "Error establishing a database connection" if the app-level user's password changed too, or everything's fine at the app layer and it's just root you can't reach for admin tasks.

Before you go further, confirm this is actually an authentication problem and not a service that's simply down:

systemctl status mysql
# or, on some distros:
systemctl status mariadb

If the service itself is crashed or won't start, that's a different fix (check journalctl -u mysql -n 50 for the real error first). This guide assumes MySQL/MariaDB is running fine and it's purely a credentials problem.

Cause

A few common ways people end up here:

  • The root password was set once during initial server setup and never written down anywhere.
  • A previous admin or developer left the team and the credentials went with them.
  • A database was restored from a snapshot or backup that had a different root password baked in.
  • Someone ran mysql_secure_installation a second time and it silently overwrote the password.
  • On newer MySQL 8 installs, root is configured for auth_socket/unix_socket authentication by default, so a password login was never going to work in the first place — you need sudo mysql, not mysql -u root -p.

That last one trips up a lot of people migrating from older MySQL 5.x setups, so rule it out first.

Fix

Step 1: Check if it's actually an auth_socket issue

On Ubuntu/Debian with MySQL 8+, root often authenticates via the Linux root user, not a password at all. Try:

sudo mysql

If that drops you straight into the MySQL prompt with no password requested, you're not locked out at all — you were just using the wrong login method. From here you can either keep using sudo mysql going forward, or switch root to password auth:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'NewStrongPassword123!';
FLUSH PRIVILEGES;

If sudo mysql also denies you, move on to the real reset below.

Step 2: Stop MySQL and start it in safe mode

This is the actual password-reset path. Stop the service first:

sudo systemctl stop mysql

Now start it with grant tables disabled, which skips privilege checks entirely and lets anyone connect without a password:

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

--skip-networking matters here — it keeps the wide-open instance off the network while you fix things, so nothing external can connect during the brief window it's unprotected.

Step 3: Log in with no password and reset root

mysql -u root

You should land at the MySQL prompt with zero authentication. From there, on MySQL 5.7+/8.x:

FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrongPassword123!';
FLUSH PRIVILEGES;

On older MariaDB versions where ALTER USER isn't available, use:

UPDATE mysql.user SET Password=PASSWORD('NewStrongPassword123!') WHERE User='root';
FLUSH PRIVILEGES;

Run SELECT VERSION(); first if you're not sure which syntax your install expects — guessing wrong just gives you a clear "unknown column" error, nothing destructive.

Step 4: Restart normally and confirm

Exit the MySQL prompt, then kill the safe-mode process and restart the service properly:

sudo mysqladmin -u root -p shutdown
sudo systemctl start mysql
mysql -u root -p

If mysqladmin shutdown hangs or fails because the safe-mode process is stubborn, find and kill it directly:

sudo pkill mysqld_safe
sudo pkill mysqld
sudo systemctl start mysql

Log in with the new password. If it works, you're done — and now is the moment to write the password down somewhere your team can actually find it.

If WordPress or other apps broke too

Resetting root doesn't touch your app-level database users (like wp_dbuser), so if a site was already down before you started, that's a separate credential to check in wp-config.php against what's actually in MySQL:

mysql -u root -p -e "SELECT User, Host FROM mysql.user;"

If the app user's password also needs resetting, do it the same way with ALTER USER 'wp_dbuser'@'localhost' IDENTIFIED BY '...'; and update wp-config.php to match.

Prevention

  • Store database credentials in a password manager or secrets vault shared with your team, not a text file on someone's laptop.
  • Before decommissioning a server or offboarding whoever set it up, rotate every credential they had access to — root MySQL included.
  • If you're restoring from a backup or snapshot regularly, document which credentials it carries so you're not guessing which password is "current."
  • Consider disabling remote root login entirely (bind-address to localhost, or drop root@'%' rows) so this account is never your attack surface, only your emergency-access account.
  • Take a quick snapshot before you start a reset like this on a production box. The process above is safe and standard, but skip-grant-tables mode briefly leaves the database open, and a snapshot gives you an instant undo if anything about your specific setup behaves differently than expected.

Frequently Asked Questions

Will this delete any data or existing databases?

No. You're only updating the authentication record for the root user in the mysql.user table. Your actual databases, tables, and application data are untouched.

Do I need to reset any other users after this?

Not automatically. Only the root password changes. If other accounts (like a WordPress database user) were separately compromised or forgotten, reset those individually the same way.

What if mysqld_safe --skip-grant-tables just hangs and never starts?

Check that the previous mysqld process actually stopped — run ps aux | grep mysql and kill any leftover process before retrying. A stale PID file or lock at /var/run/mysqld/mysqld.pid can also block a clean start; remove it if MySQL confirms it's not actually running.

Is this different on a cPanel server?

Yes. cPanel/WHM manages MySQL root access through its own layer, and resetting it there is a WHM-side task, not a raw mysqld_safe operation. This guide is specifically for self-managed VPS installs where you're talking to MySQL/MariaDB directly.

How long is the database vulnerable during --skip-grant-tables mode?

Only for the few seconds it takes you to log in and run the ALTER USER command. Using --skip-networking as shown above also blocks any remote connection during that window, so the exposure is local-only and brief.