ERROR 1045 (28000): Access denied for user 'app'@'localhost' (using password: YES) is MySQL's authentication rejection. The server was reached and understood the request; the credentials or the account itself failed. The subtlety that makes this error confusing is in the address part: MySQL accounts are a user and a host pattern together, so 'app'@'localhost' and 'app'@'%' are different accounts with potentially different passwords, and the server picks the most specific match for where the connection actually came from.
'user'@'host' in the message is the account the server matched, and it may not be the one whose password you set. A connection over the local socket matches localhost entries; the same client over TCP to 127.0.0.1 matches the TCP host rules instead, which is why “the same login” can pass one way and fail the other.SELECT user, host FROM mysql.user WHERE user = 'app'; lists the real combinations. If the combination your client matches does not exist, create it or grant appropriately; if it exists, reset that specific account's password: ALTER USER 'app'@'localhost' IDENTIFIED BY '...';.''@'localhost') can capture local connections and shadow the intended account during matching; removing unused anonymous accounts is standard hardening and a real fix for some 1045s.Root itself gets 1045 and no admin login works, what then? MySQL documents a recovery procedure: start the server with --skip-grant-tables (ideally with networking restricted), connect locally, reload the grant tables with FLUSH PRIVILEGES, and set a new root password with ALTER USER, then restart normally. It requires shell access to the server host and is a break-glass procedure, not a routine step.
Why did it break when the app moved to a container? The connection's apparent origin changed (the container's network identity, or socket versus TCP), so MySQL now matches a different user@host account, or none. The credentials did not change; the matching did.
Is 1045 a security risk or an attack? By itself it is a failed login. A flood of them in the server log from external addresses is password guessing and worth addressing at the network layer, but a single 1045 from your own application is configuration, not intrusion.