How to Reset a Forgotten MySQL/MariaDB Password (Locked-Out Recovery)
You sit down to connect to your database and the server throws `ERROR 1045 (28000): Access denied for user`. The password you were sure about no longer works, or it was never written down in the first place. When you have no working credential at all, you cannot simply run a normal `ALTER USER` — you have to recover access first.
This guide covers the locked-out recovery procedure for MySQL and MariaDB: how to start the server with authentication temporarily disabled, set a new password, and lock everything back down safely. If you still have a working admin login and just want to change a password you already know, that is a different (and much simpler) task — see .
Key Takeaways
• To reset a forgotten password you must restart MySQL/MariaDB with `–skip-grant-tables`, which bypasses the authentication system entirely.
• Always pair it with `–skip-networking` so the unauthenticated server cannot be reached over the network while it is exposed.
• After connecting without a password, run `FLUSH PRIVILEGES`, then `ALTER USER` to set the new password, then restart the service normally.
• The same procedure resets the root account or any regular user; only the username in the `ALTER USER` statement changes.
• If you still have any account with admin privileges, skip all of this and just run `ALTER USER` as that admin — no downtime required.
Why can’t I just reset a forgotten password the normal way?
MySQL and MariaDB store user credentials inside internal grant tables (in the `mysql` system database). Every connection is checked against those tables before anything else happens. To change a password with `ALTER USER` or `SET PASSWORD`, you must already be authenticated with sufficient privileges.
That creates a chicken-and-egg problem when the password is lost: you need access to change the password, but you need the password to get access. The recovery workaround is to start the database in a special mode where it does not load the grant tables at all, so any connection is accepted without credential checks. Once inside, you reload the privilege system and set a new password.
This is powerful and therefore dangerous. The recovery window is a moment when your database has effectively no authentication. Treat it accordingly.
What does `–skip-grant-tables` actually do?
When MySQL or MariaDB starts with `–skip-grant-tables`, it skips loading the privilege tables. The practical effects:
- Anyone who can reach the server connects as a full superuser — no username or password required.
- Privilege-related statements (`GRANT`, `REVOKE`, and on older versions `ALTER USER`/`SET PASSWORD`) are disabled until you run `FLUSH PRIVILEGES` to re-enable the grant system in the running process.
- The server is wide open for as long as it stays in this mode.
The detail most tutorials omit: `–skip-grant-tables` does not just relax authentication for *your* recovery session — it disables authentication for every connection the server accepts. If the server is still listening on its network port (3306 by default), anyone who can route a packet to it can connect as root during your reset. That is why you should always combine `–skip-grant-tables` with `–skip-networking`. The latter binds the server to local connections only (socket / loopback), so the unauthenticated instance is not exposed beyond the machine you are working on. Keep the window short, and never perform this on an internet-facing host without `–skip-networking`.
The step-by-step recovery procedure
The flow is the same across distributions; only the start command differs depending on whether you use systemd, mysqld_safe, or a manual override. Here is the overall sequence.
| Step | Action | Goal |
|---|---|---|
| 1 | Stop the running MySQL/MariaDB service | Free the data directory and port |
| 2 | Start it with `–skip-grant-tables –skip-networking` | Boot without authentication, locally only |
| 3 | Connect with the client (no password) | Get an unauthenticated session |
| 4 | `FLUSH PRIVILEGES` | Re-enable the grant system in the running server |
| 5 | `ALTER USER` to set the new password | Apply the new credential |
| 6 | Stop, then start the service normally | Restore authentication |
| 7 | Verify the new login and clean up | Confirm recovery and re-secure |
Step 1 — Stop the database service
Use whatever init system your server runs:
“`bash
sudo systemctl stop mysql # Debian/Ubuntu MySQL sudo systemctl stop mariadb # MariaDB sudo systemctl stop mysqld # RHEL/CentOS/Alma/Rocky MySQL “`
Confirm nothing is still running before continuing:
“`bash sudo systemctl status mysql
ps aux | grep mysqld “`
Step 2 — Start in recovery mode (pick one method)
Option A — systemd override (recommended on modern systems). Rather than editing service files, set the recovery options as an environment variable that the unit reads:
“`bash sudo systemctl set-environment MYSQLD_OPTS=”–skip-grant-tables –skip-networking” sudo systemctl start mysql “`
Option B — `mysqld_safe` (common on MariaDB and older MySQL):
“`bash sudo mysqld_safe –skip-grant-tables –skip-networking & “`
Option C — run the daemon directly as the mysql user (last resort):
“`bash sudo mysqld –skip-grant-tables –skip-networking –user=mysql & “`
Whichever you choose, the two flags together — `–skip-grant-tables` *and* `–skip-networking` — are what make this both functional and safe.
Step 3 — Connect without a password
“`bash mysql -u root “`
Because the grant tables are not loaded, no password is requested and you land at the `mysql>` prompt as a superuser.
Step 4 — Reload the privilege system
You must re-enable the grant tables in the running process before password statements will work:
“`sql FLUSH PRIVILEGES; “`
Step 5 — Set the new password
For the root account:
“`sql ALTER USER ‘root’@’localhost’ IDENTIFIED BY ‘YourNewStrongPassword’; “`
For a regular user (recover any account the same way — just change the name and host):
“`sql ALTER USER ‘appuser’@’localhost’ IDENTIFIED BY ‘YourNewStrongPassword’; “`
On some older MariaDB builds, `ALTER USER` after `–skip-grant-tables` may not behave as expected. In that case, update the credential directly and reload:
“`sql — MariaDB fallback SET PASSWORD FOR ‘root’@’localhost’ = PASSWORD(‘YourNewStrongPassword’); FLUSH PRIVILEGES; “`
If the user does not exist yet, create it instead:
“`sql CREATE USER ‘appuser’@’localhost’ IDENTIFIED BY ‘YourNewStrongPassword’; GRANT ALL PRIVILEGES ON *.* TO ‘appuser’@’localhost’ WITH GRANT OPTION; FLUSH PRIVILEGES; “`
Then exit the client:
“`sql EXIT; “`
Step 6 — Restart the service normally
Now remove the recovery mode and bring the server back with full authentication and networking restored.
If you used the systemd override in Option A, unset the variable first:
“`bash sudo systemctl unset-environment MYSQLD_OPTS sudo systemctl restart mysql “`
If you used mysqld_safe or ran the daemon directly, stop that process and start the normal service:
“`bash sudo systemctl stop mysql # or kill the mysqld_safe process sudo systemctl start mysql “`
Step 7 — Verify and re-secure
Confirm the new credential works:
“`bash mysql -u root -p
“`
If that succeeds, the recovery is complete. Make sure that:
- The server is listening on the network again (only if it is supposed to) — `–skip-networking` is gone.
- The grant tables are fully loaded — `–skip-grant-tables` is gone.
- The new password is stored in a password manager so this does not recur.
Resetting root vs resetting a regular user — what’s different?
Mechanically, nothing changes in the recovery flow. You stop the server, start it without grant tables, and run `ALTER USER` against whichever account you need. The differences are about scope and consequence:
- Root (or any superuser): losing this is the worst case because it can lock you out of administering the entire instance. Recovery via `–skip-grant-tables` is often the only route.
- A regular application user: if you still have a working admin account, you do not need the skip-grant-tables dance at all — see the safer alternative below.
A reset is also a good moment to review host scoping. `’appuser’@’localhost’` and `’appuser’@’%’` are distinct accounts with separate passwords. Reset the one your application actually connects as.
Is there a safer alternative if I still have an admin login?
Yes — and you should always prefer it. The `–skip-grant-tables` method is for the genuine locked-out scenario. If any account with sufficient privileges still works, recovering another user’s password is a single online statement with zero downtime and no authentication gap:
“`sql — Logged in as an admin who still has access: ALTER USER ‘appuser’@’localhost’ IDENTIFIED BY ‘YourNewStrongPassword’; FLUSH PRIVILEGES; “`
This is the normal, day-to-day way to rotate a password. Reserve the full recovery procedure for when no working credential exists. For the routine known-password change, see .
Security warning: keep the recovery window short
Because `–skip-grant-tables` removes all authentication, follow these guardrails every time:
- Always add `–skip-networking`. This is non-negotiable on any server reachable from a network.
- Do the reset quickly. Do not leave the server running in recovery mode while you go do something else.
- Restart into normal mode immediately after setting the password.
- Audit afterward if the host was internet-facing during the window — check connection logs for anything unexpected.
Managing MySQL recovery is straightforward on a server you fully control, but it assumes you have root/SSH access and the confidence to stop and restart system services. That is not everyone’s situation, and it should not have to be.
On DarazHost managed hosting, you rarely touch MySQL internals at all. Database users and passwords are managed safely through cPanel, where resetting a database user’s password is a few clicks with no risk of leaving an unauthenticated server exposed — and if you ever get fully locked out, our 24/7 support team can perform the recovery for you. If you need full control, DarazHost VPS and dedicated servers give you root access to run the exact `–skip-grant-tables` procedure above, with managed support available to walk through it with you. Whether you want the internals abstracted away or the keys to the whole machine, there is a plan that fits — and someone on call if a locked-out database is standing between you and your data.
Frequently asked questions
Does `–skip-grant-tables` delete my users or data? No. It only changes how the server *starts* — it skips loading the privilege tables for that session. Your users, grants, and data remain intact. Once you restart normally, the grant tables load again exactly as before, with your new password applied.
Why do I have to run `FLUSH PRIVILEGES` before `ALTER USER`? With grant tables skipped, the in-memory privilege system is not active, so password-changing statements can be rejected. `FLUSH PRIVILEGES` reloads and re-enables the grant system in the running process, allowing `ALTER USER` (or `SET PASSWORD`) to take effect.
Can I reset the password without stopping the server? Only if you still have a working account with the right privileges — then run `ALTER USER` directly, no restart needed. If you are fully locked out, there is no way around restarting into recovery mode, because every normal connection requires authentication you no longer have.
Is the procedure different for MariaDB versus MySQL? The overall flow is identical. The main differences are the service name (`mariadb` vs `mysql`/`mysqld`) and that some older MariaDB versions need the `SET PASSWORD … = PASSWORD(‘…’)` fallback instead of `ALTER USER`. Both support `mysqld_safe –skip-grant-tables`.
What if I forget the new password again later? Store it in a password manager immediately, and consider creating a second admin-level account as a break-glass credential. With two admin logins, a future reset becomes a simple online `ALTER USER` instead of a full locked-out recovery.