1045 是什么
ERROR 1045 (28000) Access denied 属于认证阶段的拒绝:TCP 已经连通、握手也完成了,服务端在核对账号身份时把这次登录挡了回来。MySQL 的账号身份由「用户名 + 来源主机」两部分组成,服务端从 mysql.user 里按 host 匹配出一条记录,再依次校验口令、认证插件、账号是否被锁以及失败次数。所以看到 1045 该先怀疑身份组合对不对,而不是服务器是否还活着。
基本信息
| 错误码 | ERROR 1045 (28000) Access denied |
|---|---|
| 触发阶段 | 连接已建立,认证校验中 |
| 完整身份 | 用户名@来源主机,两部分都要对上 |
| 常见原因 | 账号不存在、来源不匹配、口令错、插件不兼容、账号被锁 |
| 首要命令 | SELECT user,host,plugin,account_locked FROM mysql.user |
| 适用版本 | MySQL 5.7 / 8.0,MariaDB 文案基本一致 |
典型使用场景
- 新服务上线连不上库:应用来自 10.0.x 网段,却只建了 'app'@'localhost' 这条记录
- 刚改过口令的应用仍报 1045:连接池里缓存着旧凭证,重连时被服务端拒绝
- 5.7 升到 8.0 后旧客户端登录失败:默认认证插件变成 caching_sha2_password,老驱动不认识
- 接入云数据库:控制台建了账号但没配来源网段,白名单之外的来源一律 1045
- 账号因连续输错口令被临时锁定,处置前需要先 UNLOCK 解封
- 区分认证失败与授权不足:1045 表示没通过登录,1044、1142 才是登录后权限不够
定位完整身份
定位完整身份
mysql -uapp -p -h 10.0.0.5 -P 3306 # 用应用真实来源复现,记下报错里的 user@host
mysql -uroot -p -e "SELECT user,host,plugin,account_locked FROM mysql.user WHERE user='app';" # 看有几个同名账号
mysql -uroot -p -e "SHOW VARIABLES LIKE 'skip_name_resolve';" # 开启后 host 必须写 IP,写域名对不上
mysql -uapp -p -h 10.0.0.5 -D appdb -e "SELECT CURRENT_USER(), USER();" # 用成功登录的账号看实际命中身份报错文案对照
| 报错片段 | 含义 | 处置方向 |
|---|---|---|
| using password: NO | 客户端根本没带口令 | 检查 -p 的交互输入、选项文件与连接池里的密码配置 |
| using password: YES | 带了口令但校验失败 | 按命中的那条账号记录改密,或纠正来源网段 |
| Host ... is not allowed to connect | 没有任何 host 记录匹配来源 | 按来源网段建账号,例如 'app'@'10.0.%' |
| Authentication plugin ... cannot be loaded | 客户端太老,不认识服务端插件 | 升级驱动,或把该账号改为 mysql_native_password |
| Account is locked | 失败次数达到阈值被锁定 | 用 UNLOCK USER 解封,并排查是谁在不停重试 |
| Can't connect to local MySQL server | 与 1045 无关,属连接层问题 | 按 2003 的思路先查服务状态与端口监听 |
修复与验证
修复与验证
CREATE USER 'app'@'10.0.%' IDENTIFIED BY 'Str0ng#Pass!'; # 按来源网段建账号,比 % 更可控
ALTER USER 'app'@'10.0.%' IDENTIFIED WITH mysql_native_password BY 'Str0ng#Pass!'; # 老客户端兼容,按需使用
UNLOCK USER 'app'@'10.0.%'; # 失败次数锁定后的解封手段
FLUSH PRIVILEGES; # 只有直接改授权表才需要,CREATE/ALTER USER 会自动落盘
SELECT user,host,plugin,account_locked FROM mysql.user WHERE user='app'; # 改完立即核对结果host 匹配不是简单字符串相等:更具体的取值(某个 IP、10.0.%)优先于 %,% 也不匹配空主机名;localhost 走本地 socket、127.0.0.1 走 TCP,这两条路的账号记录互相独立,改了一条不等于两条都改到。
云数据库的账号与白名单通常在控制台维护,mysql.user 只能读不能改,遇到 1045 先去核对控制台里的账号来源网段与访问白名单,再回来查服务端参数。
不要为了绕开 1045 就用 --skip-grant-tables 启动实例,那等于对整片内网开放无口令管理入口;确需重置口令时必须限制来源,处置完立刻恢复正常授权并重启。
建议固定排查顺序:先用应用账号从真实来源复现、拿到完整 user@host,再核对服务端存在哪几条同名记录,最后才动授权或口令。顺序颠倒容易出现改完仍报错、也说不清改了什么的情况。