ERROR 1820和1862均表示密码过期,区别在于1862允许带过期状态登录但首条命令必须是ALTER USER,1820则因客户端不支持交互式重置而直接拒绝连接;须用ALTER USER重置密码并设PASSWORD EXPIRE NEVER,禁用SET PASSWORD或UPDATE user。

应用突然连不上 MySQL,日志里反复出现 “Access denied” 但密码没改过——八成是密码过期了,不是权限或网络问题。
ERROR 1820 或 ERROR 1862 到底意味着什么
这两个错误本质相同,都是 MySQL 在告诉你:“这个账号密码已过期,必须立刻重置”。区别在于触发时机:
-
ERROR 1862:你还能用mysql -u app_user -p登录,输完密码进到mysql>提示符,但一执行SELECT、USE就报错;说明服务端允许“带过期状态登录”,但强制首条命令必须是ALTER USER -
ERROR 1820:应用启动时连接池(如 HikariCP、Druid、pymysql)直接失败,日志只显示Access denied;因为这些客户端不支持 MySQL 的“过期密码交互式重置流程”,传完用户名密码就等着建连,无法响应服务端要求改密的指令
关键判断依据是看日志有没有 password has expired 或 must reset your password 字样。有,就不是密码错了,也不是权限漏了,就是过期了。
能登录但执行语句就报错:必须用 ALTER USER,且只能执行一次
这种情况最常见也最容易操作失误。你进了 MySQL,但所有命令都被拦截,唯一能成功的是 ALTER USER,而且它必须是登录后的第一条语句。
- ❌ 错误做法:先
USE mysql,再ALTER USER→ 直接报ERROR 1820 - ❌ 错误做法:执行
ALTER USER后顺手敲FLUSH PRIVILEGES→ 报错,MySQL 5.7+ 不需要也不允许 - ❌ 错误做法:同一连接里反复执行
ALTER USER(比如试两次密码)→ 第二次必失败 - ✅ 正确做法:登录后不敲任何其他命令,直接执行:
ALTER USER 'app_user'@'%' IDENTIFIED BY 'NewPass123!'; - ✅ 补一刀防复发:
ALTER USER 'app_user'@'%' PASSWORD EXPIRE NEVER;(仅改密码不会关掉过期策略)
执行完立刻退出重连,验证是否生效:SELECT User, Host, password_expired FROM mysql.user WHERE User = 'app_user';,确认 password_expired 是 N。
连都连不上:必须跳过权限表启动,且要加 --skip-networking
这是最紧急的情况——应用起不来,DBA 也登不进。核心不是“停服务”,而是让 mysqld 启动时不校验用户凭证。
- Linux/macOS:先
sudo systemctl stop mysql,再运行sudo mysqld_safe --skip-grant-tables --skip-networking &;--skip-networking很关键,防止远程未授权访问 - Windows:编辑
my.ini,在[mysqld]下加一行skip-grant-tables,然后重启服务 - 此时直接
mysql -u root(不加-p)就能进,不用输密码 - 进库后先
USE mysql;,再执行:ALTER USER 'app_user'@'%' IDENTIFIED BY 'NewPass123!'; - ⚠️ 注意:这种模式下
ALTER USER不自动生效,必须手动执行FLUSH PRIVILEGES; - 改完删掉
my.ini里的skip-grant-tables或杀掉mysqld_safe进程,再正常重启服务
为什么 SET PASSWORD 和 UPDATE user 都不该碰
MySQL 5.7+ 已废弃 SET PASSWORD 对过期用户的重置能力;UPDATE mysql.user 更危险,会破坏数据一致性。
-
SET PASSWORD FOR 'app_user'@'%' = PASSWORD('xxx');语法上可能不报错,但实际不更新password_expired标志位,下次登录照旧失败 -
UPDATE user SET authentication_string = ...手动改系统表,8.0+ 已移除PASSWORD()函数,且绕过权限层校验,极易导致后续FLUSH PRIVILEGES失效或用户状态异常 - 真正起作用的是
ALTER USER ... IDENTIFIED BY:它同时更新哈希值并清除password_expired = 'Y' - host 必须严格匹配:查准真实 host ——
'app_user'@'localhost'和'app_user'@'%'是两个账户;Windows 默认可能是'root'@'127.0.0.1'而非'localhost'
生产环境别指望靠“用户自己改密码”来兜底,连接池不支持交互式重置,一旦过期就是服务中断。要么全局关掉:SET PERSIST default_password_lifetime = 0;(写入配置文件,重启不失效),要么新建用户时就加 PASSWORD EXPIRE NEVER。


















