Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild
Back to Blog Troubleshooting

MySQL Error 1045: Access Denied, and the Four Things It Actually Means

Sean

Platform Writer

Jul 14, 2026
7 min read

ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) means MySQL received your credentials and rejected them. That is all it means - and crucially, it does not necessarily mean the password is wrong. MySQL identifies a user by two things, the name and the host it connects from, and a mismatch in the second one produces exactly this error with a perfectly correct password. Before you reinstall anything - and half the internet will tell you to reinstall - work through the four real causes.

MySQL Error 1045: Access Denied, and the Four Things It Actually Means

Table of contents

Read the error properly first

The message contains more information than people extract from it.

ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

'root'@'localhost' - this is the identity MySQL tried to match. Not just root: root connecting from localhost. Those are different accounts in MySQL’s model, and 'root'@'%' is a third one.

(using password: YES) - a password was supplied and rejected. If it says NO, no password reached the server at all, which is a completely different problem: your client is not sending one. That usually means you forgot -p, or a config file is overriding you, or an environment variable is empty.

That single word - YES or NO - splits the diagnosis in half, and it is the first thing to look at.

Cause 1: the host part does not match

This is the cause people miss, and it is extremely common in Docker and cloud setups.

MySQL grants are per user and host:

SELECT user, host FROM mysql.user;

+----------+-----------+
| user     | host      |
+----------+-----------+
| appuser  | localhost |
| root     | localhost |
+----------+-----------+

Here, appuser may only connect from localhost. If your application connects over TCP from another container at 172.18.0.5, MySQL looks for 'appuser'@'172.18.0.5', finds nothing, and returns 1045 - with the correct password. The credentials were never the problem.

The fix is to grant the user the host range it actually connects from:

CREATE USER 'appuser'@'172.18.%' IDENTIFIED BY 'the-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'appuser'@'172.18.%';
FLUSH PRIVILEGES;

Use the narrowest pattern that works. 'appuser'@'%' will fix the error immediately and expose the account to connections from anywhere the server is reachable, which is a poor trade if the server has a public interface.

And remember the localhost quirk: connecting to localhost uses a Unix socket, connecting to 127.0.0.1 uses TCP. The same user can succeed one way and get 1045 the other, because the two paths can match different rows in mysql.user.

Cause 2: auth_socket on Ubuntu and Debian

You set a root password during installation. You type it. Access denied. Then sudo mysql with no password works perfectly.

On Debian-family systems, MySQL’s root account is configured with the auth_socket plugin. It ignores passwords entirely and authenticates on your operating system user: if the OS says you are root, MySQL accepts you; if not, nothing you type will work.

sudo mysql -e "SELECT user, host, plugin FROM mysql.user;"

+------------------+-----------+-----------------------+
| user             | host      | plugin                |
+------------------+-----------+-----------------------+
| root             | localhost | auth_socket           |
| appuser          | localhost | caching_sha2_password |
+------------------+-----------+-----------------------+

If root shows auth_socket, the password was never going to work, and no amount of resetting it will change that.

The right response is usually to accept it - use sudo mysql for administration - because an account with no password cannot have its password stolen or guessed. If you genuinely need password auth for root:

ALTER USER 'root'@'localhost'
  IDENTIFIED WITH caching_sha2_password BY 'a-strong-password';
FLUSH PRIVILEGES;

Cause 3: the password is genuinely wrong, and how to reset it

Sometimes it is just the password. If you have lost it, you do not need to reinstall MySQL - you need to start it without authentication for sixty seconds.

Stop the server:

sudo systemctl stop mysql

Start it with authentication disabled:

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

--skip-networking matters. With --skip-grant-tables, anyone can connect as anyone with no password. Disabling the network means only local users can exploit that window, and you should keep the window short.

Connect and reset:

mysql -u root

FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'the-new-password';
FLUSH PRIVILEGES;
EXIT;

The first FLUSH PRIVILEGES is not a typo - with --skip-grant-tables the grant system is not loaded, and ALTER USER will fail until you load it.

Then restart normally:

sudo pkill mysqld
sudo systemctl start mysql

This is the correct fix. The Stack Overflow advice to “uninstall MySQL completely and delete everything” is what people do when they do not know about --skip-grant-tables, and it destroys the data along with the problem.

Cause 4: an anonymous user is shadowing you

The strangest variant. Your credentials are right, the host is right, and you still get 1045 - or, weirder, you connect successfully but can see nothing.

Some MySQL installations create an anonymous user: an entry in mysql.user with an empty user string, matching any username from a given host.

SELECT user, host FROM mysql.user WHERE user = '';

MySQL sorts its authentication rows most-specific-host-first, and an anonymous entry for '@localhost' is more specific than 'appuser'@'%'. So when appuser connects from localhost, MySQL matches the anonymous row first, tries to authenticate you as nobody, and rejects you - despite a perfectly valid 'appuser'@'%' account sitting right there.

The fix:

DROP USER ''@'localhost';
FLUSH PRIVILEGES;

This is exactly what mysql_secure_installation removes, and it is the reason that script exists. If you skipped it on a fresh install, run it now.

The diagnostic order

Work through it in this sequence and stop when it resolves.

  1. Read the (using password: ...) part. NO means your client never sent one - check for a missing -p, an empty environment variable, or a config file overriding you. That is a client problem, not a server one.
  2. Check the host. SELECT user, host FROM mysql.user; and compare against where you are actually connecting from. In Docker, this is the answer more often than not.
  3. Check the plugin. auth_socket on root means passwords are irrelevant - use sudo mysql.
  4. Look for anonymous users. SELECT user, host FROM mysql.user WHERE user = ''; and drop them.
  5. Only then reset the password, with --skip-grant-tables and --skip-networking.

What you should never do is uninstall MySQL and delete the data directory. It is the top-voted answer on some of these threads, it does technically make the error go away, and it takes your database with it.

How this fits the rest of the stack

Whatever you decide here, the cost of the decision only shows up as a bill. The RunxBuild hosting calculator is the right place to model that before committing: the compute, the database, the storage, the bandwidth, the worker - each one is a separate line item, and the real cost of a platform is the sum, not the headline number. The RunxBuild dashboard is where the team sees the actual usage once it is running.

Useful related references:

FAQ

What does MySQL error 1045 mean?

Access denied - MySQL received your credentials and rejected them. It does not necessarily mean the password is wrong. MySQL identifies users by name and host together, so a correct password with a host that has no matching grant produces exactly this error.

Why do I get error 1045 with the correct password?

Usually the host part. ‘appuser’@‘localhost’ and ‘appuser’@’%’ are different accounts. If your app connects over TCP from another container, MySQL looks for a grant matching that IP and finds none. Check SELECT user, host FROM mysql.user against where you are actually connecting from.

How do I reset a lost MySQL root password?

Stop MySQL, restart it with —skip-grant-tables —skip-networking, connect with no password, run FLUSH PRIVILEGES, then ALTER USER to set the new password, then restart normally. Do not uninstall MySQL - that destroys your data along with the problem.

Why does sudo mysql work but mysql -u root -p does not?

On Ubuntu and Debian, root uses the auth_socket plugin, which authenticates on your operating system user instead of a password. No password will ever work for that account. This is a good default - there is no root password to leak - so use sudo mysql for administration.

What is using password YES versus NO?

YES means a password was supplied and rejected. NO means no password reached the server at all, which is a client-side problem - a missing -p flag, an empty environment variable, or a config file overriding your credentials.

#mysql#error-1045#troubleshooting#database#dev-infra