How to Fix MySQL Error 1045 Access Denied: Complete Guide

Few database errors are as universally encountered — and as frequently misdiagnosed — as ERROR 1045 (28000): Access denied for user 'root'@'localhost'. The moment your application, migration script, or CLI tries to authenticate, MySQL refuses the connection and the entire request fails. Unlike a "connection refused" error, which means MySQL never answered at all, Error 1045 is an authentication failure: the TCP connection succeeded, the server accepted the handshake, and only then rejected the credentials you supplied.

That distinction matters because it tells you exactly where to look. The network is fine, the port is open, and mysqld is running — the problem lives inside MySQL's grant tables. The seven usual suspects are a wrong password, a user that does not exist, a host mismatch between where you connect from and what mysql.user allows, the caching_sha2_password plugin introduced in MySQL 8.0, privileges that were never flushed, an anonymous ''@'localhost' user shadowing the real account, or root login restrictions on modern distributions. This guide walks through each cause and the exact commands to resolve it.

What is MySQL Error 1045?

MySQL Error 1045 is returned by the server's authentication subsystem after the TCP connection has already been established. The full message typically reads ERROR 1045 (28000): Access denied for user 'user'@'host' (using password: YES). The SQLSTATE 28000 is the standard code for "invalid authorization specification," and the trailing (using password: YES) (or NO) tells you whether the client actually sent a password at all — a valuable clue when the failure is caused by a missing password in a connection string rather than a wrong one.

Because authentication happens after the transport layer, Error 1045 proves the server is reachable and listening. You should not spend time checking firewalls, bind-address, or whether mysqld is running; those produce Error 2002 or 2003, not 1045. Instead, focus on the triplet MySQL checks on every login: the username, the host the connection originates from, and the password (including the plugin that hashes it). A mismatch on any one of the three returns 1045.

One subtlety: MySQL matches the host before the password. If you connect as appuser from 10.0.0.5 but the grant table only contains 'appuser'@'localhost', MySQL may report 1045 rather than 1130, because it never finds a matching row to validate the password against. This is why the Host column is the first thing to inspect.

Common Causes

Error 1045 traces back to a small, predictable set of root causes. Recognizing which one applies to your situation is usually faster than trial-and-error password resets:

Step-by-Step Fix Guide

Step 1: Confirm the exact error and identify the user and host

Read the full error message and note the user and host MySQL reports, not the ones you think you are using. The quoted 'user'@'host' in the message is the identity MySQL tried to match. Reproduce the failure with the CLI so you control every parameter:

mysql -u root -p
# or, for a specific user and host:
mysql -h 127.0.0.1 -P 3306 -u appuser -p appdb

If the message ends with (using password: NO), the client never sent a password — check your connection string for a missing or empty password field before doing anything else.

Step 2: Verify the user exists and check allowed hosts

Log in as an administrative user and inspect the grant tables. The Host column is what trips up most people: a user defined only for localhost cannot connect from a remote address.

sudo mysql   # works on Ubuntu where root uses auth_socket
# then inside MySQL:
SELECT User, Host, plugin FROM mysql.user WHERE User = 'appuser';

-- If no rows return, the user does not exist. Create it:
CREATE USER 'appuser'@'%' IDENTIFIED BY 'a-strong-password';

If the user exists only as 'appuser'@'localhost' and you connect remotely, create a matching 'appuser'@'%' account — or, better, one scoped to a specific subnet such as 'appuser'@'10.0.0.%'.

Step 3: Reset the password with ALTER USER

When the password is wrong or unknown, reset it explicitly with ALTER USER. This is the modern, recommended replacement for the deprecated SET PASSWORD syntax:

ALTER USER 'appuser'@'%' IDENTIFIED BY 'new-strong-password';
FLUSH PRIVILEGES;

If you have lost the root password entirely, restart MySQL with --skip-grant-tables to bypass authentication, reset root, then restart normally:

sudo systemctl stop mysql
sudo mysqld_safe --skip-grant-tables --skip-networking &
mysql -u root
# inside MySQL, run:
#   ALTER USER 'root'@'localhost' IDENTIFIED BY 'new-root-password';
#   FLUSH PRIVILEGES;
sudo systemctl start mysql

Step 4: Fix the authentication plugin mismatch

MySQL 8.0+ defaults new users to caching_sha2_password. If your client or driver does not support it, Error 1045 appears even with a correct password. Switch the user to the legacy plugin, or — preferably — upgrade the client:

-- Switch a user back to the legacy plugin (quick fix for old clients)
ALTER USER 'appuser'@'%' IDENTIFIED WITH mysql_native_password
  BY 'a-strong-password';

-- Or set the global default for new users in my.cnf:
-- [mysqld]
-- default_authentication_plugin = mysql_native_password

Prefer upgrading the client over downgrading security: caching_sha2_password is faster and uses SHA-256. The legacy plugin is acceptable only as a temporary compatibility shim for clients you cannot immediately upgrade.

Step 5: Remove anonymous user conflicts

Many default installations create an anonymous ''@'localhost' account. MySQL matches grant rows in order, and the empty-user row can win over the real account, causing a baffling 1045 with a password you know is correct. Remove it:

-- Find anonymous users
SELECT User, Host FROM mysql.user WHERE User = '';

-- Drop them
DROP USER ''@'localhost';
DROP USER ''@'localhost.localdomain';
FLUSH PRIVILEGES;

Step 6: Flush privileges and test the connection

On MySQL 5.7 and earlier, direct edits to the grant tables are not live until you reload them. Even though CREATE USER, ALTER USER, and GRANT reload automatically in modern versions, flushing is harmless and rules out a stale grant table as the cause:

FLUSH PRIVILEGES;

-- Verify the effective grants for the account
SHOW GRANTS FOR 'appuser'@'%';
# Finally, test from the exact host the application uses:
mysql -h db.example.com -P 3306 -u appuser -p appdb

MySQL Diagnostic Commands

These commands form a complete diagnostic loop for Error 1045. Run them in order to pinpoint the failing triplet of user, host, and plugin:

# 1. Connect as root (Ubuntu/Debian auth_socket allows sudo)
sudo mysql -u root

# 2. Test a specific user's login interactively
mysql -u appuser -p appdb
-- 3. List every account, its host, and its auth plugin
SELECT User, Host, plugin FROM mysql.user;

-- 4. Show the privileges granted to a specific account
SHOW GRANTS FOR 'appuser'@'%';

-- 5. Check the default authentication plugin in effect
SHOW VARIABLES LIKE 'default_authentication_plugin';

-- 6. Confirm who you are currently authenticated as
SELECT CURRENT_USER(), USER();

The difference between CURRENT_USER() (the grant-table identity matched) and USER() (the identity you requested) is a powerful clue: if they differ, an anonymous or wildcard host row matched your connection instead of the account you intended.

Quick Reference Table

Symptom Cause Fix
ERROR 1045 for a single user only Wrong or rotated password ALTER USER ... IDENTIFIED BY
1045 for root@localhost on Ubuntu auth_socket plugin blocks password login Use sudo mysql or switch plugin
Works locally, 1045 remotely User defined as 'user'@'localhost' only Create 'user'@'%' or specific host
1045 after MySQL 8 upgrade caching_sha2_password unsupported by client ALTER USER ... IDENTIFIED WITH mysql_native_password
1045 right after GRANT Privileges not reloaded (5.7 and earlier) FLUSH PRIVILEGES
Correct password still rejected Anonymous ''@'localhost' shadowing DROP USER ''@'localhost'

FAQ

How do I reset a forgotten MySQL root password?

Stop MySQL, restart it with --skip-grant-tables --skip-networking, connect as root without a password, run ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpassword';, then restart MySQL normally. On systemd distributions, use sudo systemctl set-environment MYSQLD_OPTS="--skip-grant-tables" before restarting the service for a clean lifecycle.

Why does MySQL 8 reject users that worked fine in MySQL 5.7?

MySQL 8.0 changed the default authentication plugin from mysql_native_password to caching_sha2_password. Users created fresh on 8.0 get the new plugin, and older clients that cannot perform the SHA-2 handshake receive Error 1045 even with the right password. Either upgrade the client library or switch the user with ALTER USER ... IDENTIFIED WITH mysql_native_password.

Is it safe to use mysql_native_password instead of caching_sha2_password?

It is acceptable as a compatibility measure, but caching_sha2_password is more secure (SHA-256) and faster on repeated logins thanks to its in-memory cache. Use the legacy plugin only for clients you cannot immediately upgrade, and treat setting default_authentication_plugin = mysql_native_password in my.cnf as a temporary bridge rather than a permanent policy.

Why do I still get 1045 after running GRANT?

Three reasons. First, GRANT cannot operate on a user that does not exist in MySQL 8.0 — create it with CREATE USER first. Second, you may have granted to 'user'@'localhost' while connecting from a different host. Third, an anonymous ''@'localhost' row can match before your intended user. Inspect SELECT User, Host FROM mysql.user; and run FLUSH PRIVILEGES; to rule out a stale grant table.

Conclusion

MySQL Error 1045 is an authentication-layer rejection, which is good news: it means your server is reachable and the fix lives entirely in the grant tables. Work through the triplet MySQL validates on every login — username, host, and password (with its hashing plugin) — and the cause almost always reveals itself. Confirm the exact error and host, verify the user exists with the right Host value, reset the password with ALTER USER, resolve any caching_sha2_password mismatch, remove anonymous users that shadow real accounts, and finish with FLUSH PRIVILEGES and a real connection test.

The most common mistake is treating 1045 as a network problem. It is not. If you can reach the port, the issue is credentials or grants — and the commands above will resolve the overwhelming majority of cases in minutes rather than hours.

Related Guides