- Error number
- 1045
- SQLSTATE
28000- Symbol
ER_ACCESS_DENIED_ERROR- Product
- MySQL Server
- Versions
- MySQL 5.7, 8.0 and 8.4 (in 8.4 also for accounts that use the disabled mysql_native_password plugin)
- Category
- Access & Privileges
- Last reviewed
- 24 October 2026
On this page
What it means
Error 1045 means the server found no account that matches this user name, client host and password (or authentication method), so it refused the login.
A MySQL account is a user name and a host: 'app'@'localhost' and 'app'@'10.0.0.%' are two separate accounts with their own passwords and privileges. When a client connects, the server takes the user name it sent and the host it sees the client coming from, picks the most specific matching row in mysql.user, and checks the credentials with that account's authentication plugin. If no row matches or the check fails, the client gets 1045. The message deliberately looks the same for a wrong password and for a user that does not exist, so it does not reveal which accounts exist.
Read the message closely. The first part is the user name the client sent; the second is the client host as the server sees it, which is not always what you typed (in our runs, connecting to 127.0.0.1 was reported as 'localhost', because the server resolved the address to that name). using password: NO means no password was sent at all, often a missing -p or an empty variable in a configuration file; YES means one was sent, not that it was correct. In PHP the SQLSTATE shows as HY000, because connection errors are reported before a session exists.
Common causes
- The password is wrong or out of date, for example after a password change that not every application or option file picked up.
- No password is sent (using password: NO): the
-poption is missing, or the password setting in the application is empty. - The account exists for a different host: there is
'app'@'localhost'but the client connects over the network, or the account was created for one IP and the client's address changed. - A more specific account wins the match. The manual's classic case is an anonymous
''@'localhost'account that is chosen instead of'app'@'%'for local connections, so the password of the anonymous account is checked. - The client reads other credentials than you expect from an option file such as my.cnf or the [client] section (test with
--no-defaults). - On MySQL 8.4, the account uses mysql_native_password, which is disabled by default there, so its logins fail with 1045.
Diagnose it
Read-only These statements only read metadata (information_schema, performance_schema and SHOW statements) or your own data. They do not change data, privileges or configuration, so they are safe to run first.
Which accounts exist for this user name, and for which hosts?
Run as an administrator. Never select or share the authentication_string column: it holds the password hash.
SELECT user, host, plugin, account_locked, password_expired, password_last_changed
FROM mysql.user
WHERE user = 'app'
ORDER BY host; Compare each host value with the host in the error message. No row whose host matches that client means the account is missing for that host (or the client host is not what you think). account_locked Y gives error 3118 rather than 1045. The plugin column shows how the password is checked.
Anonymous accounts that can shadow a named one
SELECT user, host, plugin
FROM mysql.user
WHERE user = ''
ORDER BY host; Ideally no rows. An anonymous account for localhost is more specific than 'app'@'%' and is used instead for local connections, which produces 1045 with a correct password.
Once connected: which account did you get?
When a login works from one place but not another, connect where it works and compare.
SELECT USER() AS sent_as, CURRENT_USER() AS authenticated_as;
SHOW GRANTS FOR CURRENT_USER(); USER() is the name and host the client presented; CURRENT_USER() is the account row that matched. If they differ (for example app@localhost against app@%), the host part is the reason logins behave differently from other places.
How many logins are failing, and from where?
SELECT error_number, error_name, sum_error_raised, first_seen, last_seen
FROM performance_schema.events_errors_summary_global_by_error
WHERE error_number IN (1045, 3118);
SELECT ip, host, count_authentication_errors, sum_connect_errors, last_error_seen
FROM performance_schema.host_cache
WHERE count_authentication_errors > 0
ORDER BY count_authentication_errors DESC; The number of 1045 errors since the server started and when the last one happened. The host cache adds failed authentications per remote client address (it does not track local or loopback connections). Many failures from an unknown address can mean password guessing.
Which password plugins are available?
SELECT plugin_name, plugin_status
FROM information_schema.plugins
WHERE plugin_name LIKE '%password%'; An account whose plugin (from the first query) is not ACTIVE here cannot log in. This matters after an upgrade to MySQL 8.4, where mysql_native_password is disabled by default.
How to fix it
Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.
Send the right credentials, and only those
Client or network sideCheck the user, host, port and password the application really uses. With the mysql client, test with --no-defaults so no option file adds old values, and use -p to be prompted for the password. Make sure the host you connect to is the server you think it is (a different server has different accounts).
-- mysql --no-defaults -h 127.0.0.1 -P 3306 -u app -p
Create the account for the host the client really connects from
Changes permissionsIf the account exists only for another host, add one for the actual client host or subnet and grant it only what the application needs.
Caution: Avoid '%' (any host) and never use GRANT ALL ON *.* for an application account. Use the narrowest host pattern that works and only the privileges the application needs.
CREATE USER 'app'@'10.0.0.%' IDENTIFIED BY 'a-long-random-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'app'@'10.0.0.%';
Reset the application password, then update every client at once
Changes permissionsIf the password is lost or out of sync, set a new one and roll it out to every application and option file that uses this account.
Caution: Every client still using the old password starts failing with 1045 immediately. Change it at a planned time, and keep passwords in a secrets store rather than in code.
ALTER USER 'app'@'10.0.0.%' IDENTIFIED BY 'a-new-long-random-password';
Move accounts off mysql_native_password before (or after) upgrading to 8.4
Changes permissionsIn MySQL 8.4 mysql_native_password is disabled by default, and the manual lists it as deprecated from MySQL 8.0.34. Switch such accounts to caching_sha2_password, the default plugin in MySQL 8.0, and make sure the client libraries support it (current connectors do).
Caution: caching_sha2_password needs a secure connection (TLS, a Unix socket file or shared memory) or RSA key exchange for the first login after the password is set; otherwise the client gets error 2061 (Authentication requires secure connection). Test one client first.
ALTER USER 'app'@'10.0.0.%' IDENTIFIED WITH caching_sha2_password BY 'a-long-random-password';
Remove a shadowing anonymous account
Changes permissionsIf the second check found ''@'localhost', removing it lets the named account match. Anonymous accounts are also a security risk in their own right.
Caution: Confirm first that nothing relies on anonymous logins (they are rarely wanted). DROP USER removes the account and its privileges at once.
DROP USER ''@'localhost';
Examples
A login that does not exist (a password is sent)
Run with the mysql 8.0.46 client. The host in the message is localhost although the client connected to 127.0.0.1: the server reports the client host by name when it can resolve it.
-- From a command prompt (cws_errlab_nouser is not an account on this server):
-- mysql -h 127.0.0.1 -u cws_errlab_nouser -p
SELECT 1;
ERROR 1045 (28000): Access denied for user 'cws_errlab_nouser'@'localhost' (using password: YES)
Reproduced on MySQL 8.0.46, 24 October 2026.
No password sent at all
An empty --password= sends no password, so the message says using password: NO. The client also printed mysql: [Warning] Using a password on the command line interface can be insecure.
-- mysql -h 127.0.0.1 -u cws_errlab_nouser --password=
SELECT 1;
ERROR 1045 (28000): Access denied for user 'cws_errlab_nouser'@'localhost' (using password: NO)
Reproduced on MySQL 8.0.46, 24 October 2026.
MySQL 8.4: an account that still uses mysql_native_password
Shown as documented in the MySQL 8.4 reference manual (Native Pluggable Authentication); not reproduced here, because the lab server is MySQL 8.0 and the lab may not create accounts. The manual adds that the server writes these errors to its error log.
-- On MySQL 8.4 with mysql_native_password disabled (the default):
-- mysql -u userx -p
ERROR 1045 (28000): Access denied for user 'userx'@'localhost' (using password: NO)
How to prevent it
Give each application its own account with an explicit host pattern and only the privileges it needs, keep the password in one secrets store that every instance reads, and rotate it with a plan that updates all consumers together. Remove anonymous accounts, and check for mysql_native_password accounts before upgrading to MySQL 8.4.
Watch failed logins: a sudden rise in 1045 in events_errors_summary_global_by_error or in the host cache after a deployment usually means a stale password, while steady failures from unknown addresses suggest someone guessing passwords. For broader hardening see the SQL security lesson.
Common questions
How do I fix MySQL error 1045 access denied?
Check the user and host in the message against SELECT user, host FROM mysql.user (as an administrator). If no row matches that host, create the account for the right host; if it matches, the password is wrong, so reset it and update every client. Test with mysql --no-defaults -p to rule out old option files.
What does using password: NO mean?
The client did not send a password. Either you left out -p, the application's password setting is empty, or the account you meant needs one. It does not say anything about whether the account exists.
Why does root get 1045 right after installing MySQL?
Most installers set a root password, or a temporary one written to the error log, so a login without a password is refused. Use mysql -u root -p with that password. If it is lost, follow the reset procedure in the MySQL manual rather than switching off authentication.
What is the difference between 1045 and 1130?
1130 means no account at all exists for the client host, and the server refuses before asking for a user name. 1045 means at least one account could match the host, but the user name and password (or plugin) did not authenticate.
Learn more on CodeWithSQL
Official documentation
- Troubleshooting problems connecting to MySQL
- Access control, stage 1: connection verification
- Specifying account names
- Native pluggable authentication (MySQL 8.4)
Last technically reviewed 24 October 2026; examples and diagnostics run on MySQL 8.0.46. Message templates checked against the server's error catalogue (perror) for that version.