密码过期是导致应用突然无法连接MySQL 8.0的主因,日志出现“password has expired”即可确认;需用ALTER USER重置密码并设PASSWORD EXPIRE NEVER,或全局禁用default_password_lifetime=0。

应用突然连不上 MySQL 8.0,日志里反复出现 Access denied for user,但密码没改过——基本就是密码过期了,不是权限或网络问题。
看错误日志有没有 password has expired 或 must reset your password
这是最直接的判断依据。MySQL 8.0+ 在拒绝连接时,错误日志(通常是 hostname.err)里会明确写 “password has expired”。如果没开错误日志,先确认 log_error_verbosity = 3 并重启 mysqld;否则可能只看到模糊的 Access denied,误判为密码输错。
注意:Java 应用(如用 HikariCP、Druid)或 Python(pymysql)根本不会响应 MySQL 的“改密交互流程”,所以一旦过期,连接池初始化就卡死,不会给你任何提示性报错,只会循环重试 Access denied。
能登录但执行语句就报 ERROR 1820,怎么快速修复
说明你还能用 mysql -u root -p 登录,但账户处于“过期待重置”状态。此时必须用 ALTER USER,且这条语句必须是登录后的**第一条且唯一命令**。
- ❌ 错误操作:先
USE mysql、再SELECT ...、或顺手敲FLUSH PRIVILEGES—— 全部触发ERROR 1820 - ✅ 正确做法:登录后立刻执行
ALTER USER 'app_user'@'%' IDENTIFIED BY '新密码';,然后退出重连 - ⚠️ host 必须完全匹配:查准是
'app_user'@'localhost'还是'app_user'@'127.0.0.1',Windows 下常见后者;不确定时可临时用'app_user'@'%'(仅限测试) - ?
IDENTIFIED BY会同时更新密码哈希和清除password_expired标志位;SET PASSWORD在 8.0+ 对过期用户无效,别用
连都连不上,只能跳过权限表启动
这是最紧急的情况:应用起不来,DBA 也登不进。核心不是“停服务”,而是“以无校验方式启动 mysqld”,关键要加 --skip-networking 防止暴露未授权访问面。
- Linux/macOS:停服务后,用
mysqld --skip-grant-tables --skip-networking --datadir=/var/lib/mysql &启动 - Windows:在服务管理器里停止 MySQL 服务,然后以管理员身份运行命令行,执行同上命令
- 启动成功后,本地用
mysql -u root(不加-p)直连,立即执行ALTER USER 'app_user'@'%' PASSWORD EXPIRE NEVER; - 改完必须正常重启 mysqld,不能一直挂着
--skip-grant-tables
如何一劳永逸避免再踩坑
别等出事才救,重点在预防:
- 全局禁用策略:
SET PERSIST default_password_lifetime = 0;(写入mysqld-auto.cnf,重启不失效) - 新建用户时就关掉:
CREATE USER 'app_user'@'%' IDENTIFIED BY 'xxx' PASSWORD EXPIRE NEVER; - 已有用户批量处理:
SELECT CONCAT('ALTER USER ''', User, '''@''', Host, ''' PASSWORD EXPIRE NEVER;') FROM mysql.user WHERE password_expired = 'Y';,生成并执行结果 - ⚠️ 注意:
password_lifetime = NULL不等于永不过期,它继承全局值;只有= 0才是真正安全的“永不过期”
真正麻烦的从来不是改密码,而是连接池不支持交互式重置流程——所以永远别指望“用户自己登录改一下”,得从策略源头掐断过期机制。


















