Users and privileges
A MySQL account includes its host
Match an account to the real connection source and use specific remote hosts with TLS instead of normalizing the percent wildcard.
MySQL treats 'notes_app'@'localhost' and 'notes_app'@'10.0.0.24' as different accounts. An account is the pair of user name and host, never the name alone. Always write the full account name in CREATE USER, GRANT, SHOW GRANTS, and REVOKE.
The host part answers one question: where may this connection come from? When a client connects, the server looks for an account whose host matches the connection’s origin. No matching host means no matching account, and the login fails even with the correct password.
Use localhost when the application and MySQL share a machine. For a remote application, use its specific private host or network pattern and require TLS:
CREATE USER 'notes_app'@'10.0.0.24'
IDENTIFIED BY 'replace-with-a-generated-secret'
REQUIRE SSL;
REQUIRE SSL rejects unencrypted connections for this account. Credentials that cross a network should never travel in plain text.
See which accounts exist
List every account for a user name:
SELECT user, host FROM mysql.user WHERE user = 'notes_app';
The output makes duplicates visible. If you see both localhost and % rows for the same user, they are separate accounts with separate passwords and separate grants.
The wrong fix
Here is the classic trap. The application moves to a new server and logins start failing:
ERROR 1045 (28000): Access denied for user 'notes_app'@'10.0.0.31' (using password: YES)
The password is correct. The problem is that the account was created for 10.0.0.24, and the connection now arrives from 10.0.0.31. The error message shows you the real origin, which is exactly the evidence you need.
The % host wildcard accepts every source host. Do not use it as the normal fix for a failed connection. It converts a precise access rule into “anyone who knows the password, from anywhere.” Check DNS, network rules, TLS, and the real application source first, then create the account for the host the error message reported.
Lesson completed