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.
Table of contents
- Read the error properly first
- Cause 1: the host part does not match
- Cause 2: auth_socket on Ubuntu and Debian
- Cause 3: the password is genuinely wrong, and how to reset it
- Cause 4: an anonymous user is shadowing you
- The diagnostic order
- How this fits the rest of the stack
- FAQ
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.
- Read the
(using password: ...)part.NOmeans 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. - 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. - Check the plugin.
auth_socketon root means passwords are irrelevant - usesudo mysql. - Look for anonymous users.
SELECT user, host FROM mysql.user WHERE user = '';and drop them. - Only then reset the password, with
--skip-grant-tablesand--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:
- MySQL Port: 3306 Default, Change, and Multi-Version Setup
- Error Logs: The Part That Is the Operations Truth, and the Part That Is Just Noise
- MySQL Pivot: There Is No PIVOT, So Here Is What to Do Instead
- Managed databases on RunxBuild
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.