MySQL 8.0+ 的 mysql.user 表中无 last_login 字段,真正可用的是 performance_schema.accounts 表的 LAST_SEEN(需启用相关消费者),或 events_connections_history_long 表中 EVENT_TYPE='connect' 的 EVENT_TIME;二者均非原生登录时间字段,须手动配置日志插件或开启 Performance Schema 才能获取。

查账户最后一次登录时间用哪个字段?
MySQL 8.0+ 的 mysql.user 表里没有直接记录登录时间的字段,last_login 字段只在启用 mysql_native_password 插件且开启审计日志时才可能更新,多数生产环境为空。真正可用的是 Performance Schema 的 events_statements_summary_by_account_by_event_name 或更稳妥的 performance_schema.account_statistics(MySQL 8.0.28+),但该表默认关闭且需手动启用。
- 启用前先确认版本:
SELECT VERSION(); - 若 ≥ 8.0.28,执行:
UPDATE performance_schema.setup_actors SET ENABLED = 'YES' WHERE HOST = '%';,再重启收集(注意:这不会回溯历史,只从启用后开始计) - 更通用的做法是查
information_schema.PROCESSLIST中近期活跃连接,或结合操作系统层面的审计日志(如 Linuxauth.log配合 MySQL 登录命令)
用 SELECT 找出 90 天没登录的账户怎么写?
没有现成登录时间字段时,只能靠间接线索判断“疑似僵尸”:
- 检查账户是否被显式禁用:
SELECT User, Host, account_locked FROM mysql.user WHERE account_locked = 'Y'; - 查密码过期时间:
SELECT User, Host, password_expired, password_last_changed FROM mysql.user WHERE password_last_changed < DATE_SUB(NOW(), INTERVAL 90 DAY) OR password_expired = 'Y'; - 排除系统账户(如
'mysql.infoschema'、'mysql.session')和空密码账户(authentication_string = ''或plugin = 'auth_socket'且无密码需求) - 注意:不要仅凭
password_last_changed判定——它只反映密码修改时间,不等于登录时间;有些账号密码十年没改但每周都在用
清理前必须验证的三件事
直接 DROP USER 很危险,尤其跨应用共享账号时:
- 确认该账号未被任何应用配置文件硬编码(搜代码库里的
config.yml、.env、Spring Boot 的application.properties) - 检查是否被视图、存储过程、事件调度器引用:
SELECT * FROM information_schema.VIEWS WHERE VIEW_DEFINITION LIKE '%username%'; - 在低峰期先锁定而非删除:
ALTER USER 'xxx'@'%' ACCOUNT LOCK;,观察 3–7 天是否有报警或失败连接日志(SHOW GLOBAL STATUS LIKE 'Aborted_connects';可辅助判断)
MySQL 5.7 怎么办?
5.7 完全没有 account_statistics 或 last_login,只能靠外部手段补足:
- 开启 general_log(仅临时):
SET GLOBAL general_log = 'ON'; SET GLOBAL log_output = 'TABLE';,然后查mysql.general_log中最近的Connect事件(但日志体积大、影响性能,切勿长期开启) - 用 pt-heartbeat 或自建连接日志表,让应用每次连接时写入时间戳
- 最现实的做法:把账号按业务线分类,联系各负责人确认使用状态,再批量处理;别指望数据库自己记住谁“没来过”
清理僵尸账户不是纯 SQL 任务,本质是权限治理+协作流程。漏掉一个还在用的账号,比留十个不用的账号后果更严重。


















