mysqlseverity: workaround
1045

MySQL Error 1045: Access denied for user

Access denied for user (using password: YES)

88% fixable~15 mindifficulty: intermediate

Verified against MySQL 9.0 docs (error-codes), Stack Overflow #1412284, MySQL Reference Manual · Updated April 2026

> quick_fix

The MySQL user/password combo is invalid, OR the user exists but isn't allowed to connect from your host. First confirm the credentials, then check if a user exists for the host you're connecting from.

-- Connect as root (adjust host as needed)
mysql -u root -p

-- See all users and their host permissions
SELECT user, host FROM mysql.user WHERE user = 'your_user';

-- Create a user for your specific host (or use % for any)
CREATE USER 'your_user'@'%' IDENTIFIED BY 'your_password';
GRANT ALL ON your_db.* TO 'your_user'@'%';
FLUSH PRIVILEGES;

What causes this error

MySQL authenticates the triple (user, password, host). Error 1045 fires if any of the three is wrong. Common gotcha: `alice@localhost` and `alice@%` are different users. If you created `alice@localhost` and try to connect from another machine, MySQL returns 1045 even with the right password.

> advertisementAdSense placeholder

How to fix it

  1. 01

    step 1

    Confirm the exact credentials

    Re-type the password (no copy-paste — invisible characters can sneak in). Confirm the user spelling.

  2. 02

    step 2

    Check which host patterns exist for the user

    Log in as root and query mysql.user. The host pattern matters — `alice@localhost` only allows connections from the server itself.

    SELECT user, host FROM mysql.user WHERE user = 'alice';
  3. 03

    step 3

    Create or update the user for your connecting host

    If no row matches your host, create one. Use % to allow any host (common for dev; restrict in production).

  4. 04

    step 4

    For reset passwords: use ALTER USER

    Don't use UPDATE mysql.user on MySQL 8+. Use ALTER USER with the correct auth plugin.

    ALTER USER 'alice'@'%' IDENTIFIED BY 'newpassword';
    FLUSH PRIVILEGES;

Why 1045 happens at the runtime level

MySQL's authentication plugin (caching_sha2_password by default in 8.0+) checks the connection against the mysql.user table using a tuple of (user, host, password_hash). The host column supports wildcards and IP patterns. When a connection arrives, the server's acl_authenticate function in sql/auth/sql_authentication.cc resolves the most-specific matching host pattern for the requested user, then validates the password. If no host pattern matches the connecting client's address (after PTR lookup), or if the password hash mismatches, the server returns ER_ACCESS_DENIED_ERROR (1045). The 'using password: YES/NO' suffix indicates whether the client offered a password at all, not whether it was correct.

Common debug mistakes for 1045

  • Creating user@'%' and assuming it covers localhost, MySQL prefers the more specific user@'localhost' row if it exists, and connecting via the unix socket always matches localhost, so % is silently bypassed.
  • Resetting the password via UPDATE mysql.user SET password = ..., this column was removed in MySQL 5.7+; the correct path is ALTER USER which goes through the auth plugin's hash routine.
  • Forgetting FLUSH PRIVILEGES after direct table edits, but if you used CREATE USER / GRANT / ALTER USER, FLUSH is automatic and unnecessary; conflicting advice in old docs causes time waste.
  • Connecting from a Docker container by IP and not realising the host pattern needs to match the container's NAT-translated address, not the docker0 bridge, common cause of 1045 in CI.
  • Using mysql_native_password expecting compatibility with old clients, MySQL 8.4+ removed this plugin entirely, so legacy clients can't authenticate even with the right password.

When 1045 signals a deeper problem

1045 errors that pile up across services usually mean credentials are managed by ad-hoc copy-paste rather than a secrets workflow. When dev, staging, and prod each have separately-created users with different host patterns and rotation schedules, the team accumulates orphaned grants and ghost privileges. The architectural fix is a secrets manager (Vault, AWS Secrets Manager, Doppler) that issues database credentials per-application via dynamic secrets, short-lived users created on demand with the exact grants needed. This kills the 'whose password was it' triage cycle and gives auditable access logs. Without it, every service migration sparks a new round of 1045s.

Editor's take

This error has a particular fondness for striking during production deploys at 11pm when the platform team lead just handed off to an on-call junior dev. The classic scenario: a startup migrating from a single-server MySQL 5.7 setup to RDS MySQL 8.0 with a separate application user. The MYSQL_USER and MYSQL_PASSWORD environment variables are correct in .env.local but nobody ported them to the ECS task definition or Kubernetes secret. The app boots, healthcheck passes on localhost, and then every real connection attempt from the container subnet hits 1045 because the user was created with host='localhost' not host='%'.

Hitting this error and actually diagnosing it — not just rotating credentials until something works — is a meaningful skill signal. A junior dev treats it as a password problem and starts guessing. Someone one to two years in learns about the (user, host) tuple from this exact incident and never forgets it. The deeper insight — that MySQL 8.0's default caching_sha2_password plugin can cause 1045-alike failures with older client libraries even when credentials are correct — is what separates someone who understands the auth stack from someone who just runs MySQL. Running SELECT user, host, plugin FROM mysql.user is the move; not resetting the password.

This error rarely arrives alone. Upstream you will often find ERROR 2003 (Can't connect to MySQL server) or ERROR 2005 (Unknown MySQL server host) if DNS or network is also misbehaving, which masks the real 1045. Downstream, application-level connection pool exhaustion surfaces as HikariPool-1 - Connection is not available or sequelize ConnectionAcquireTimeoutError after the pool retries against a permanently-rejected user. In Kubernetes environments, a related SECRET mis-mount often co-occurs — meaning a second service in the same namespace is silently using a stale secret version and will fail on its next pod restart.

By Bikram Nath · Curator · Updated April 2026

Frequently asked questions

Why does MySQL say access denied for root with no password?

MySQL 8+ installs root with auth_socket (on Ubuntu) — you can only log in as the actual OS root via `sudo mysql`. Set a password with ALTER USER to enable standard password auth.

What does "using password: YES" mean?

It means you supplied a password but it was wrong (or the user/host didn't match). "using password: NO" means you connected with no password at all.

How do I reset the MySQL root password if I'm completely locked out?

Stop the MySQL service, restart it with `--skip-grant-tables` flag, connect without a password using `mysql -u root`, run `FLUSH PRIVILEGES;` then `ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';`, and restart MySQL normally. On MySQL 8.0+, you can also use `--init-file` with a SQL file containing the ALTER USER statement for a safer approach.

disclosure:Errordex runs AdSense, has zero third-party affiliate or sponsored links, and occasionally links to the editor’s own paid digital products (clearly labelled). Every fix is cross-referenced against the official sources listed in the “sources” sidebar before it ships. If a fix here didn’t work for you, please email so we can update the page.