TechEarl

How to Reset a Forgotten MySQL Root Password

Recover a MySQL root account with a temporary init file or isolated recovery startup, then remove the recovery settings and verify normal authentication.

Ishan Karunaratne⏱️ 8 min readUpdated
Share thisCopied
Terminal showing MySQL root account recovery and authentication checks

For a forgotten MySQL root password, first check whether an existing administrator or local socket-authenticated root account can still log in. If so, change the password through that authorized connection. Otherwise, schedule downtime and start the correct MySQL instance temporarily with an init file or --skip-grant-tables. Remove every recovery setting before returning the service to normal operation.

Do not leave a password-reset SQL file referenced from my.cnf. It contains a plaintext credential and runs again at startup. I previously described that as a permanent reset method; that advice was wrong. The recovery file and startup override must be temporary.

Check the account and instance first

On installations configured for local socket authentication, this may already work:

bash
sudo mysql --protocol=socket

This is a check of the existing configuration, not an authentication bypass. If it succeeds, inspect the account before deciding to change its authentication method:

sql
SELECT CURRENT_USER(), @@version, @@socket, @@datadir;
SELECT User, Host, plugin FROM mysql.user WHERE User = 'root';

'root'@'localhost' and 'root'@'another-host' are different accounts. An auth_socket account uses the operating-system identity; a forgotten SQL password is not necessarily the problem. If a password-authenticated account needs a new password, an authorized administrator can use ALTER USER without restarting the server.

For offline recovery, identify the service name, server binary, configuration file, data directory, runtime user and socket. Preserve a tested backup and stop application writes. Never start a second server on a data directory that another server is using.

The shell examples below assume one self-managed MySQL 8.0/8.4 instance on Linux, a mysql service/user, /etc/mysql/my.cnf and /var/lib/mysql. Adapt those paths to the actual instance. They are not instructions for MariaDB, managed database services, Windows services or every container image.

Recover with a temporary init file

This is the recovery method I would try first when normal administrative login is unavailable. It retains privilege checking while applying one controlled account change during startup.

Stop the identified service, create a private temporary file and edit it locally. Do not put the real password in a shell argument, a browser input or a shared terminal transcript.

bash
sudo systemctl stop mysql
sudo install -o mysql -g mysql -m 600 /dev/null /var/lib/mysql/te-recovery.sql
sudoedit /var/lib/mysql/te-recovery.sql

Put a single SQL statement in the file, replacing the example string with a new unique password:

sql
ALTER USER 'root'@'localhost' IDENTIFIED BY 'REPLACE_WITH_A_NEW_UNIQUE_PASSWORD';

IDENTIFIED BY selects the server's default authentication plugin; it does not promise to retain a nondefault plugin. Inspect the account and choose a supported plugin explicitly when the authentication method matters. For a deliberate migration to caching_sha2_password on MySQL 8.0/8.4:

sql
ALTER USER 'root'@'localhost'
  IDENTIFIED WITH caching_sha2_password BY 'REPLACE_WITH_A_NEW_UNIQUE_PASSWORD';

Do not run both statements mechanically. Choose the one appropriate to the account. For this temporary SQL literal, a long random password without quote or backslash characters avoids SQL escaping ambiguity; store it in a password manager. A server password policy can reject the change, so inspect startup errors and verify the resulting login.

Start the server with its existing configuration and a separate recovery socket. --defaults-file belongs first among the options. The explicit server user avoids creating root-owned database files.

bash
sudo install -d -o mysql -g mysql -m 755 /run/mysqld
sudo /usr/sbin/mysqld --defaults-file=/etc/mysql/my.cnf \
  --user=mysql --skip-networking \
  --socket=/run/mysqld/te-recovery.sock \
  --pid-file=/run/mysqld/te-recovery.pid \
  --init-file=/var/lib/mysql/te-recovery.sql &

Wait for this instance's ready message, not a fixed sleep. AppArmor/SELinux rules or a different package layout can reject a recovery path; use a permitted private location rather than disabling the host's security controls. The process still needs its normal storage, keyring and log configuration.

Verify an authenticated query through the recovery socket. -p prompts without exposing the password in the process arguments:

bash
mysql --protocol=socket --socket=/run/mysqld/te-recovery.sock \
  -u root -p -e 'SELECT CURRENT_USER(), @@version;'

After the successful reset, delete the plaintext file. Shut down that instance through its socket, then start the normal service:

bash
sudo rm -- /var/lib/mysql/te-recovery.sql
mysqladmin --protocol=socket --socket=/run/mysqld/te-recovery.sock \
  -u root -p shutdown
sudo systemctl start mysql
mysql --protocol=socket -u root -p -e 'SELECT CURRENT_USER(), @@version;'

Wait for shutdown to finish before starting the service. If recovery fails partway through, clean up the file and recovery process before retrying. Do not use pkill mysqld: it can stop unrelated instances. If you added a temporary service/configuration override, remove it as well; deleting its SQL file while leaving init-file configured can prevent the next startup.

Alternative: temporary privilege-table bypass

This procedure is scoped to MySQL 8.0/8.4. It temporarily disables authorization and should be limited to a controlled maintenance window. Any local user able to reach its socket may gain broad access.

Stop the normal service and start the same identified instance with its normal configuration, but without the init-file option:

bash
sudo systemctl stop mysql
sudo install -d -o mysql -g mysql -m 755 /run/mysqld
sudo /usr/sbin/mysqld --defaults-file=/etc/mysql/my.cnf \
  --user=mysql --skip-grant-tables --skip-networking \
  --socket=/run/mysqld/te-recovery.sock \
  --pid-file=/run/mysqld/te-recovery.pid &

Use a client session with history disabled while entering the replacement password:

bash
MYSQL_HISTFILE=/dev/null mysql --protocol=socket \
  --socket=/run/mysqld/te-recovery.sock -u root

Inspect the account, reload privileges, then change the appropriate password-authenticated account:

sql
SELECT User, Host, plugin FROM mysql.user WHERE User = 'root';
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'REPLACE_WITH_A_NEW_UNIQUE_PASSWORD';

FLUSH PRIVILEGES makes account-management statements available in this recovery session. Use an explicit supported plugin only when the account actually needs that migration; do not downgrade authentication to make an old client work.

Verify a new authenticated connection, use mysqladmin against the recovery socket to shut it down, then start the regular service as above. Confirm no skip-grant-tables setting remains in a config file, container command or service override.

Remove persistent recovery settings

The former persistent-reset procedure is withdrawn. There is no reason to keep a root password in a persistent startup SQL file. Use the temporary recovery procedure above, remove the file, and restore the normal startup configuration.

Version compatibility: 5.7, 8.0, 8.4

Server/accountWhat changes
MySQL 8.0 password accountALTER USER ... IDENTIFIED BY sets the password using the server's default plugin. Name a supported plugin explicitly if required; verify clients can authenticate.
MySQL 8.4mysql_native_password is built in but disabled by default. The old default_authentication_plugin server option is removed. A reset is not a reason to enable native authentication.
MySQL 9.0 and latermysql_native_password has been removed. Use the manual for the exact deployed release when planning account/client migration.
Older MySQL 5.7ALTER USER is supported; direct edits to mysql.user are not a universal prerequisite. Do not copy the 8.x plugin examples onto 5.7. Plan an upgrade separately.
Socket-authenticated rootCheck authorized local socket login first. Changing to password authentication is a separate configuration choice.

The earlier article also conflated 5.5/5.6 and 5.7 privilege-table layouts. I have removed that compatibility promise rather than imply this procedure was tested against every old server.

Verify and re-lock the server

Run the normal service with no recovery options. Through an authenticated administrative connection, check:

sql
SELECT CURRENT_USER(), @@version, @@socket, @@datadir;
SELECT User, Host, plugin FROM mysql.user WHERE User = 'root';
SHOW VARIABLES LIKE 'init_file';

The temporary init_file should be unset (empty or NULL). Confirm the running process and startup configuration contain neither recovery option. A fresh connection using the intended credential must succeed; for a password-authenticated root account, a fresh connection with no password or an incorrect password must fail. An absent skip_grant_tables row from SHOW VARIABLES is not proof that bypass is disabled on every supported version. Confirm the temporary file is gone, the service restarts normally, and application users still connect with their own restricted accounts. Review logs for failures without copying credentials into a ticket.

I checked both recovery methods in disposable MySQL 8.0.46 and 8.4.11 containers on September 23, 2026. The checks covered old/new credentials, a normal restart, deletion of the init file, and continued access for a restricted application account. They did not exercise a host systemd unit, AppArmor/SELinux policy, replication or a managed service.

Containers and managed databases

A container often has no systemctl, and its main process controls the container lifetime. Preserve its configuration and data volume, stop the original container, and use the image's documented recovery startup options. Never run two containers against the same writable MySQL data volume. Merely running these host commands inside docker exec is not a portable recovery procedure.

For managed MySQL, use the provider's supported password-reset controls. This article does not grant access to its host or underlying root account. MariaDB has different authentication defaults and requires its own recovery procedure.

What to do next

Use separate least-privilege application accounts; the MySQL cheat sheet covers account and privilege management. A WordPress user's forgotten password is a different problem: use the WordPress password-reset guide, not database-root recovery.

Sources

Authoritative references this article was fact-checked against.

TagsMySQLDatabasePassword ResetRoot PasswordMySQL AdminAuthenticationSecurity

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Systems and Network Architect · Chief Technology Officer

Systems and network architect and Chief Technology Officer with more than two decades designing, building, and running production software, cloud and network architecture, Linux systems, and the bare metal underneath them, and lately working AI into the stack. A US Army veteran who served in Operation Iraqi Freedom. What I write here is drawn from the full arc of that work, across architecture, engineering, and operations, not any single job.

Keep reading

Related posts

Four reliable ways to change a WordPress password: admin dashboard, WP-CLI, direct in the database, or email reset. Includes the WP 6.8+ bcrypt hash format.

How to Change a WordPress Password

Four reliable ways to change a WordPress password: admin dashboard, WP-CLI, directly in the database with the correct phpass or bcrypt hash, and the lost-password email reset.