mysql 8.0+ 查看用户密码过期时间需查 mysql.user 表的 password_expired、password_last_changed 和 password_lifetime 字段,需具备 mysql 库 select 权限,推荐语句:select user, host, password_expired, password_last_changed, password_lifetime from mysql.user。

MySQL 8.0+ 查看用户密码过期时间的正确方式
MySQL 5.7 及更早版本不支持密码过期策略,只有 MySQL 8.0+ 才真正通过 password_expired、password_last_changed 和 password_lifetime 等字段支持细粒度控制。直接查 mysql.user 表能拿到基础状态,但要注意字段含义和权限限制。
-
password_expired是布尔值('Y'/'N'),表示当前是否强制要求重置密码(由ALTER USER ... PASSWORD EXPIRE或到期自动触发) -
password_last_changed是时间戳,记录上次改密时间;结合账号的password_lifetime(全局或用户级)才能算出预计过期时间 - 必须有
SELECT权限在mysql数据库,普通用户默认无权查询 —— 常见错误是用应用账号执行SELECT * FROM mysql.user报错Access denied - 全局
default_password_lifetime值可通过SHOW VARIABLES LIKE 'default_password_lifetime'查看,默认为 0(永不过期)
执行查询时必须加 WHERE 过滤,否则可能被拒绝
即使有权限,MySQL 8.0 默认也会隐藏敏感字段(如 authentication_string)在 mysql.user 中显示为 NULL,但 password_expired 和 password_last_changed 是可读的。关键是要避免全表扫描式查询引发权限校验失败。
- 推荐语句:
SELECT user, host, password_expired, password_last_changed, password_lifetime FROM mysql.user - 如果只想看已过期或即将过期的用户,加条件:
WHERE password_expired = 'Y' OR (password_last_changed IS NOT NULL AND password_lifetime > 0 AND DATE_ADD(password_last_changed, INTERVAL password_lifetime DAY) - 注意:当
password_lifetime为NULL,说明该用户继承全局设置;为 0 表示永不过期,不参与计算
如何判断某个用户是否“实际过期”而非仅标记为 expired
password_expired = 'Y' 是显式状态(管理员手动设置或策略触发),但“实际过期”需动态计算:当前时间是否超过 password_last_changed + password_lifetime。这个逻辑不能只靠 SQL 表达式完全覆盖,尤其当 password_lifetime 为 NULL 时得回查全局变量。
- 先查用户级设置:
SELECT password_lifetime FROM mysql.user WHERE user = 'xxx' AND host = 'yyy' - 若结果为
NULL,再查全局:SHOW VARIABLES LIKE 'default_password_lifetime' - 然后用
DATE_ADD(password_last_changed, INTERVAL ? DAY)和NOW()比较 —— 注意时区一致性,确保 MySQL 服务器时区与业务预期一致(SELECT @@time_zone) - 常见坑:应用连接池复用旧连接后,即使密码已过期,首次查询仍可能成功,直到下一次认证(如重连或执行
FLUSH PRIVILEGES后)才报ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.
低权限用户无法自查,只能依赖 DBA 提供视图或存储过程
普通账号没有 mysql.user 的 SELECT 权限,SELECT USER(), CURRENT_USER() 也只返回登录名和匹配的授权行,不暴露过期信息。DBA 若想让开发自查,需显式授权或封装。
- 安全做法:创建只读视图,例如
CREATE VIEW user_password_status AS SELECT user, host, password_expired, password_last_changed FROM mysql.user,再授权给特定角色 - 更实用的是写个存储过程,输入用户名,内部用
SELECT ... INTO判断并返回明确提示(如 "expired" / "expires_in_3_days" / "never") - 切勿用
GRANT SELECT ON mysql.* TO ...—— 这等于开放所有系统表,风险极高
MySQL 的密码过期不是“到期即锁”,而是下次认证时拦截;且 password_last_changed 不会因 SET PASSWORD 外的任何操作更新(比如 ALTER USER ... IDENTIFIED BY 才会刷新它)。别指望从慢日志或 general_log 里捞出过期线索 —— 它只发生在连接建立阶段。











