error 1045主因是mysql.user表中缺失'root'@'localhost'记录、host匹配失败、plugin不兼容或account_locked='y';须查host/user/authentication_string/plugin/account_locked五字段并验证socket/tcp连接路径。

直接看 mysql.user 表的变更记录,但 MySQL 默认不保留历史 —— 所以真正能定位权限故障的,是日志 + 时间线交叉比对。
查 general_log 或 audit log 里的 GRANT/REVOKE 语句
MySQL 不会自动记录谁改了权限,除非你提前开了日志。生产环境强烈建议开启 general_log(临时)或专用审计插件(如 mysql_enterprise_audit)。没开?那就只能靠碰运气:检查是否有备份的 mysql.user 快照,或从 binlog 解析 DDL(仅限开启了 binlog_format=ROW 且 log_bin_trust_function_creators=ON 的极少数场景)。
-
general_log是最实用的:设为 ON 后所有语句(包括GRANT、REVOKE)都会写入文件或表,用grep -i 'grant\|revoke' /var/lib/mysql/general.log就能快速定位操作人、时间、目标账号 - 如果用的是 MySQL 8.0+ 企业版,
audit_log更精准,能过滤出access_denied和grant类事件 - 别依赖
slow_query_log—— 权限语句执行快,不会进慢日志
对比 user 表中不同 host 的权限状态
错误 ERROR 1045 (28000): Access denied for user 'root'@'localhost' 却能连 'root'@'%',本质是 MySQL 把 localhost 和 127.0.0.1 当成两个用户处理。必须分别查:
SELECT user, host, authentication_string, account_locked FROM mysql.user WHERE user = 'root';- 重点看
host字段是否包含'localhost'、'127.0.0.1'、'%'—— 缺任何一个,对应连接方式就失效 -
account_locked = 'Y'会导致密码正确也拒绝登录,容易被忽略
验证连接方式与认证路径是否匹配
本地应用报错但命令行能连?大概率是 socket vs TCP 认证走岔了。MySQL 对 localhost 默认走 Unix socket,而 -h 127.0.0.1 强制走 TCP —— 这两种路径查的是 user 表里不同的 host 行。
- 确认应用连接串用的是
host=localhost还是host=127.0.0.1(有些 ORM 默认填 localhost) - 检查
my.cnf中skip-name-resolve是否启用 —— 若未启用,MySQL 会尝试反向解析客户端 IP,失败时可能延迟或误判 host - 用
mysql --protocol=socket -u root -S /var/lib/mysql/mysql.sock和mysql --protocol=tcp -h 127.0.0.1 -u root分别测试,看哪个失败
权限故障最难缠的点不在“改没改”,而在“改了哪一行”。root@localhost 和 root@% 是两条独立记录,REVOKE ALL ON *.* FROM 'root'@'localhost' 不影响其他 host —— 但业务代码往往硬编码了连接方式,根本意识不到自己在用哪条记录登录。











