Fix: Access denied for user 'root'@'localhost' (MySQL ERROR 1045)
The Error
You try to connect to MySQL and get:
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)Or one of these variations:
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)Access denied for user 'myuser'@'localhost' (using password: YES)Access denied for user 'root'@'127.0.0.1' (using password: YES)SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES)All of these mean the same thing: MySQL rejected your login credentials. The server is running and reachable, but it won’t let you in.
Why This Happens
MySQL authenticates users based on three things: username, host, and authentication method (password or plugin). A mismatch in any of these causes ERROR 1045.
Common causes:
- Wrong password. The password you’re providing doesn’t match what MySQL has stored for that user.
- The root account uses
auth_socketorunix_socketinstead of a password. On Ubuntu/Debian, MySQL and MariaDB often configure root to authenticate via the OS user, not a password. Runningmysql -u root -pfails because root expects socket auth, not a password. caching_sha2_passwordplugin incompatibility. MySQL 8.0+ defaults tocaching_sha2_password, which older clients and libraries don’t support.- Host mismatch. MySQL treats
'root'@'localhost','root'@'127.0.0.1', and'root'@'%'as different accounts. You may have set the password for one but are connecting as another. - The user doesn’t exist. The user account was never created, or was dropped.
- Docker MySQL root password not set or not matching. The
MYSQL_ROOT_PASSWORDenvironment variable doesn’t match what you’re using to connect. - Application connection string has wrong credentials. The password in your
.envfile, config, or connection string is stale or incorrect.
Fix 1: Use the Correct Password
Start with the obvious. Make sure you’re using the right password.
If you set a root password during installation:
mysql -u root -pMySQL will prompt for the password. Type it carefully — the terminal won’t show any characters.
If you’re passing the password on the command line (not recommended for production):
mysql -u root -p'yourpassword'Note: no space between -p and the password.
“using password: NO” means you didn’t provide a password at all. Either add -p to prompt for one, or check your connection string.
“using password: YES” means you provided a password, but it’s wrong.
Fix 2: Fix the Auth Plugin (auth_socket / unix_socket)
On Ubuntu, Debian, and many Linux distributions, MySQL and MariaDB configure the root account to use auth_socket (MySQL) or unix_socket (MariaDB) authentication by default. This means root can only log in as the OS root user — no password required, but only via sudo.
This works:
sudo mysqlThis fails with ERROR 1045:
mysql -u root -pCheck the current auth plugin
sudo mysql -e "SELECT user, host, plugin FROM mysql.user WHERE user='root';"You’ll see something like:
+------+-----------+-----------------------+
| user | host | plugin |
+------+-----------+-----------------------+
| root | localhost | auth_socket |
+------+-----------+-----------------------+Switch root to password authentication
sudo mysqlFor MySQL 8.0+:
ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'your_new_password';
FLUSH PRIVILEGES;For MySQL 5.7 or if your clients don’t support caching_sha2_password:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_new_password';
FLUSH PRIVILEGES;For MariaDB:
ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('your_new_password');
FLUSH PRIVILEGES;Now mysql -u root -p works with your new password.
Alternative approach: Instead of switching root to password auth, create a separate admin user and keep root on socket auth. This is actually more secure:
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'strong_password';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;Fix 3: Reset the Root Password (skip-grant-tables)
If you’ve lost the root password entirely, reset it using safe mode.
Step 1: Stop MySQL
Linux (systemd):
sudo systemctl stop mysql
# or for some distributions:
sudo systemctl stop mysqldmacOS (Homebrew):
brew services stop mysqlWindows:
net stop MySQL80Step 2: Start MySQL with —skip-grant-tables
This starts MySQL without any authentication checks.
Linux:
sudo mysqld_safe --skip-grant-tables --skip-networking &The --skip-networking flag prevents remote connections while the server is running without authentication. This is critical for security.
macOS:
sudo mysqld_safe --skip-grant-tables --skip-networking &Windows: Open an elevated Command Prompt:
mysqld --skip-grant-tables --skip-networkingStep 3: Connect and reset the password
mysql -u rootFor MySQL 8.0+:
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'your_new_password';For MySQL 5.7:
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'your_new_password';For older MySQL versions (5.6 and below):
FLUSH PRIVILEGES;
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('your_new_password');FLUSH PRIVILEGES must come first when running with --skip-grant-tables, or the ALTER USER command fails.
Step 4: Restart MySQL normally
Kill the safe mode process and restart:
sudo killall mysqld
sudo systemctl start mysqlTest the new password:
mysql -u root -pFix 4: Fix caching_sha2_password Issues (MySQL 8.0+)
MySQL 8.0 changed the default authentication plugin from mysql_native_password to caching_sha2_password. Many older clients, libraries, and ORMs don’t support this plugin and fail with ERROR 1045 or a related authentication error.
Symptoms
Your client shows one of these:
Authentication plugin 'caching_sha2_password' cannot be loadedERROR 1045 (28000): Access denied for user 'root'@'localhost'Option A: Switch the user to mysql_native_password
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password';
FLUSH PRIVILEGES;Option B: Change the server default for all new users
Edit my.cnf (or my.ini on Windows):
[mysqld]
default_authentication_plugin=mysql_native_passwordOn MySQL 8.4+, this setting was replaced:
[mysqld]
authentication_policy=mysql_native_passwordRestart MySQL after editing.
Option C: Update your client
The better long-term solution is to update your MySQL client library to one that supports caching_sha2_password:
- PHP: Use
mysqlnd(PHP 7.4+) or upgrade to PHP 8.x. - Python: Use
mysql-connector-python8.0+ orPyMySQL1.0+. - Node.js: Use
mysql2instead ofmysql. - Java: Use MySQL Connector/J 8.0+.
Fix 5: Fix Host Mismatches
MySQL treats these as completely different user accounts:
'root'@'localhost'— connects via Unix socket or TCP tolocalhost'root'@'127.0.0.1'— connects via TCP to127.0.0.1'root'@'%'— connects from any host
You may have set a password for 'root'@'%' but you’re connecting to localhost, which uses the 'root'@'localhost' account (with a different — or no — password).
Check which user accounts exist
SELECT user, host, plugin FROM mysql.user;Create the missing account or fix the password
If 'root'@'127.0.0.1' is missing:
CREATE USER 'root'@'127.0.0.1' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'127.0.0.1' WITH GRANT OPTION;
FLUSH PRIVILEGES;If the password is wrong on one of them:
ALTER USER 'root'@'127.0.0.1' IDENTIFIED BY 'your_password';
FLUSH PRIVILEGES;How to tell which host you’re connecting from
mysql -u root -p(no-hflag) uses the Unix socket on Linux/macOS, which matches'root'@'localhost'.mysql -u root -p -h 127.0.0.1uses TCP, which matches'root'@'127.0.0.1'.mysql -u root -p -h localhostuses the Unix socket on Linux, TCP on Windows.
To force TCP even with localhost:
mysql -u root -p -h 127.0.0.1 --protocol=TCPFix 6: Fix Docker MySQL Root Password
Docker MySQL containers set the root password via environment variables at first startup only. Changing the environment variable after the data volume already exists has no effect.
Check your docker-compose.yml or docker run command
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: your_password
ports:
- "3306:3306"Or:
docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=your_password -p 3306:3306 mysql:8.0Common Docker mistakes
Connecting from the host to the container:
mysql -u root -p -h 127.0.0.1 -P 3306Use 127.0.0.1, not localhost. On Linux, localhost tries the Unix socket, which doesn’t connect to the container.
Connecting from another container:
Use the service name as the hostname, not localhost (see ERR_CONNECTION_REFUSED on localhost for why localhost doesn’t work across containers):
mysql://root:your_password@db:3306/mydbPassword was changed but old volume persists:
If you change MYSQL_ROOT_PASSWORD and the container still rejects your login, the password was set during the first initialization and is stored in the data volume.
Fix it by removing the volume and reinitializing:
docker compose down -v
docker compose up -dWarning: This deletes all data in the MySQL volume. Export your data first if needed.
Or reset the password inside the running container:
docker exec -it mysql mysql -u root -p -e "ALTER USER 'root'@'%' IDENTIFIED BY 'new_password'; FLUSH PRIVILEGES;"MYSQL_ALLOW_EMPTY_PASSWORD vs MYSQL_ROOT_PASSWORD:
If you set MYSQL_ALLOW_EMPTY_PASSWORD=yes, root has no password. Connect with:
mysql -u root -h 127.0.0.1Not with -p.
Fix 7: Fix Application Connection Strings
Your code connects fine from the command line but your app gets ERROR 1045. The problem is usually in the connection string or environment variable.
Check your connection string format
mysql://user:password@host:port/databaseCommon issues:
- Special characters in the password need to be URL-encoded.
p@ss#wordbecomesp%40ss%23word. - The port is wrong. Default is
3306, but Docker may map it to a different port. - The host is wrong. Inside Docker, use the container/service name. From the host, use
127.0.0.1.
Check your environment variables
Make sure your app is actually reading the right config. A common mistake is having the password in .env but the app reading from a different config file, or the environment variable not being loaded.
# Print the DATABASE_URL (mask the password in production)
echo $DATABASE_URLPHP (PDO) specific
// Wrong -- password has special characters that break parsing
$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'root', 'p@ss');
// Right -- use the options array
$pdo = new PDO('mysql:host=127.0.0.1;dbname=mydb;charset=utf8mb4', 'root', 'p@ss');Note: PHP’s PDO with localhost uses the Unix socket. Use 127.0.0.1 to force TCP, especially in Docker setups.
Still Not Working?
The anonymous user is shadowing your account
MySQL may have an anonymous user (''@'localhost') that takes priority over your named account. This is common on older MySQL installations.
Check for anonymous users:
SELECT user, host FROM mysql.user WHERE user = '';If any rows return, delete them:
DROP USER ''@'localhost';
DROP USER ''@'%';
FLUSH PRIVILEGES;Run mysql_secure_installation to clean up other default security issues.
MySQL is reading a different config file
MySQL reads options files from multiple locations. A stale password in ~/.my.cnf or /etc/mysql/conf.d/ can override what you’re typing.
Check which config files MySQL reads:
mysql --help | grep -A 1 "Default options"Look for a [client] section with a hardcoded password:
[client]
user=root
password=old_wrong_passwordRemove or update it.
The user exists for a different host only
You have 'myuser'@'%' but the connection resolves to localhost, and MySQL prefers more specific host matches. A 'myuser'@'%' account does not match connections from localhost if there’s any other entry for localhost (even the anonymous user).
Fix it by creating the localhost-specific account:
CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost';
FLUSH PRIVILEGES;MySQL data directory has wrong permissions
After a manual installation, upgrade, or restore, the MySQL data directory may be owned by the wrong user. This is a common file permission issue on Linux:
ls -la /var/lib/mysqlIt should be owned by mysql:mysql. Fix it:
sudo chown -R mysql:mysql /var/lib/mysql
sudo systemctl restart mysqlSELinux is blocking MySQL (RHEL/CentOS/Fedora)
SELinux may prevent MySQL from reading its data files or socket:
sudo ausearch -m avc -ts recent | grep mysqlIf you see denials:
sudo setsebool -P mysql_connect_any 1
sudo restorecon -rv /var/lib/mysqlTemporary password expired (fresh MySQL 8.0 install)
On fresh MySQL 8.0 installations (especially on RHEL-based systems), MySQL generates a temporary root password. You must change it before doing anything else.
Find the temporary password:
sudo grep 'temporary password' /var/log/mysqld.logLog in with it:
mysql -u root -pMySQL forces you to change it immediately:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourNewStrongPassword!1';The new password must meet MySQL’s validate_password policy (uppercase, lowercase, digit, special character, at least 8 characters). To lower the policy for development:
SET GLOBAL validate_password.policy = LOW;
SET GLOBAL validate_password.length = 6;Related: If you’re troubleshooting database connectivity beyond authentication, see Fix: PostgreSQL Connection Refused. For Docker networking and file issues, see Fix: Docker COPY Failed: File Not Found and Fix: Docker Permission Denied. If your app can’t read the database credentials from environment variables, see Fix: Environment Variable Is Undefined.
Related Articles
Fix: MySQL ERROR 2002 (HY000): Can't connect to local MySQL server through socket
How to fix MySQL ERROR 2002 (HY000) when the MySQL client can't connect through the Unix socket file on Linux, macOS, Docker, and WSL.
Fix: psql: error: connection to server refused (PostgreSQL)
How to fix 'could not connect to server: Connection refused', 'psql: error: connection to server at localhost port 5432 failed', and other PostgreSQL connection refused errors on Linux, macOS, Windows, and Docker.
Fix: Docker Volume Permission Denied – Cannot Write to Mounted Volume
How to fix Docker permission denied errors on mounted volumes caused by UID/GID mismatch, read-only mounts, or SELinux labels.
Fix: MySQL Too Many Connections – Error 1040
How to fix the MySQL error 1040 'Too many connections' by adjusting max_connections, fixing connection leaks, and optimizing connection pooling.