MySQL无原生“到期自动失效”账号机制,本质是通过ACCOUNT EXPIRE(8.0.12+)或PASSWORD EXPIRE AFTER N(8.0.11+)触发新连接拦截,账号与权限仍存在;需先确认版本≥8.0.12才可用ACCOUNT EXPIRE设绝对到期日,否则退选PASSWORD EXPIRE AFTER N,并务必SET PERSIST default_password_lifetime = 0防覆盖。

MySQL 没有“到期自动失效”的账号机制,所谓有效期,本质是密码过期触发登录拦截——账号本身不会被删、权限也不会被回收,只是新连接进不来。真要让第三方工具在指定日期后彻底连不上,必须用 ACCOUNT EXPIRE(8.0.12+)或 PASSWORD EXPIRE AFTER N(8.0.11+),且必须配合应用层兜底。
确认 MySQL 版本是否支持 ACCOUNT EXPIRE
这是最关键的前置动作。低于 8.0.12 的版本(包括所有 5.7 及更早版本)根本不识别 ACCOUNT EXPIRE,执行会直接报错 ERROR 1064 (42000),而不是静默忽略。
- 先查版本:
SELECT VERSION();—— 返回值必须 ≥8.0.12 - 如果返回
5.7.32或8.0.11,就别用ACCOUNT EXPIRE,改用PASSWORD EXPIRE AFTER N(仅限 8.0.11+)或放弃原生方案 - 注意:
SHOW VARIABLES LIKE 'version%';和SELECT @@version;效果等同,选一个就行
用 ACCOUNT EXPIRE 设置绝对到期日(推荐用于明确截止场景)
适合给第三方运维账号设“2026-06-30 前有效”这类硬性截止时间。它不依赖密码修改历史,只看系统日期是否超过设定值。
- 新建账号并设到期日:
CREATE USER 'ops_tool'@'10.20.%' IDENTIFIED BY 'p@ss2026' ACCOUNT EXPIRE '2026-06-30'; - 修改已有账号:
ALTER USER 'ops_tool'@'10.20.%' ACCOUNT EXPIRE '2026-06-30'; - 立即过期(等效禁用):
ALTER USER 'ops_tool'@'10.20.%' ACCOUNT EXPIRE NOW; - 验证是否生效:
SELECT User, Host, account_locked, password_expired FROM mysql.user WHERE User = 'ops_tool';—— 过期后password_expired为Y,但account_locked仍为N
用 PASSWORD EXPIRE AFTER N 设置相对有效期(兼容性稍好)
适用于“创建后 7 天内有效”这类场景,8.0.11+ 即可使用,但注意它和全局 default_password_lifetime 冲突。
- 必须显式关闭全局策略,否则可能被覆盖:
SET PERSIST default_password_lifetime = 0; - 建号时指定:
CREATE USER 'ops_tool'@'10.20.%' IDENTIFIED BY 'p@ss2026' PASSWORD EXPIRE AFTER 7; - 该语法不接受日期字符串,只认整数天;也不能写成
AFTER '2026-06-30',会语法错误 - 第三方工具若不处理
ERROR 1820(绝大多数都不处理),首次连接就会失败,无法执行任何语句
为什么 GRANT/REVOKE 或 DROP USER 不是“临时权限”解法
很多人误以为授权时加个时间参数或定时删用户就能实现临时权限,实际完全行不通。
-
GRANT SELECT ON app.* TO 'ops_tool'@'10.20.%';—— 权限一旦授予,永远存在,没有时间维度 -
DROP USER 'ops_tool'@'10.20.%';—— 是彻底删除,不是暂停;且主从延迟可能导致从库权限残留 - 用
EVENT自动DROP USER看似可行,但要求event_scheduler=ON,且已建立的长连接(如工具的连接池)不会中断,数据仍在被读取 - 真正可控的只有登录环节:过期 → 新连接拒绝 → 工具无法建连 → 权限自然失效
最易被忽略的一点:第三方运维工具通常不重试或不处理 ERROR 1820,所以账号一过期,它就彻底失联,连告警都发不出来。如果你需要“过期前通知”或“宽限期”,只能靠外部调度器(如 cron)提前查 mysql.user 表 + 主动发消息,MySQL 本身不提供这类能力。


















