Skip to main content

Fixed: "ERROR 1045 (28000): Access denied" for an Account with REQUIRE SSL in MySQL

· 4 min read
Jagdish Kumawat
Founder @ Dewiride

The password was right, and I still got ERROR 1045 (28000): Access denied. MySQL gives no hint of the real reason: this account has REQUIRE SSL, and the connection didn't use TLS. It caught me over a local socket too, which require_secure_transport would have allowed.

What I Was Doing​

I'd set an account in MySQL 9.7 to need TLS:

mysql>
ALTER USER 'inventory_app'@'%' REQUIRE SSL;

Then I signed in the way I always do in this project, inside the container:

Terminal
docker compose exec mysql mysql --user=inventory_app --password

What I Expected​

A session: the password hadn't changed, and a local socket is secure.

What I Got​

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

The mysql client refused with ERROR 1045: Access denied for user inventory_app@localhost (using password: YES), with the right password.

What I Checked​

The account, as root:

mysql>
SELECT user, host, ssl_type FROM mysql.user WHERE user = 'inventory_app';
Output
+---------------+------+----------+
| user | host | ssl_type |
+---------------+------+----------+
| inventory_app | % | ANY |
+---------------+------+----------+
1 row in set (0.000 sec)

ssl_type isn't empty, so the account has a requirement.

The same login with TLS, over TCP:

Terminal
mysql --user=inventory_app --password --protocol=TCP --host=127.0.0.1 --ssl-mode=REQUIRED --table --execute "SELECT CURRENT_USER() AS account"
Output
+-----------------+
| account |
+-----------------+
| inventory_app@% |
+-----------------+

So the password was right all along.

TCP with TLS off: the same error, from 127.0.0.1:

Output
ERROR 1045 (28000): Access denied for user 'inventory_app'@'127.0.0.1' (using password: YES)

Why It Happens​

MySQL's Access denied is deliberately vague, so it doesn't tell someone trying passwords which part was wrong. REQUIRE SSL applies to the account itself, and it needs an actual TLS connection, so a socket doesn't count. That's the difference from require_secure_transport, a server-wide setting that does accept sockets.

The Fix​

Connect with TLS. For the mysql client inside the container, that means going over TCP, as above. For an app, set SslMode in its connection string.

Or remove the requirement, if you need the socket, and use the server-wide setting instead:

mysql>
ALTER USER 'inventory_app'@'%' REQUIRE NONE;
SET PERSIST require_secure_transport = ON;

After the Fix​

With REQUIRE NONE:

Output
+---------------+------+----------+
| user | host | ssl_type |
+---------------+------+----------+
| inventory_app | % | |
+---------------+------+----------+
1 row in set (0.000 sec)

The account's ssl_type empty after ALTER USER REQUIRE NONE.

Common Mistakes​

MistakeWhat happensDo this instead
Resetting the passwordThe new one's refused as wellCheck ssl_type
Assuming a socket is enoughREQUIRE SSL wants TLSUse TCP with TLS
Setting it on an account a script uses over a socketThe script stops signing inUse require_secure_transport

Troubleshooting​

SymptomLikely causeFix
ssl_type says X509 or SPECIFIEDIt needs a client certificate as wellHow to Require a Client Certificate for a MySQL Account
ssl_type is empty, and it's still deniedIt really is the passwordThe fix
The password in the container's variable is wrongYour shell overrode .envThe fix

Conclusion​

An account with REQUIRE SSL gets a plain ERROR 1045 without TLS, even over a socket. Check ssl_type, and connect with TLS.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.