MySQL本身不记录用户登录时间,所谓“僵尸账号”必须依赖业务表(如user_login_log中的last_login_at字段);mysql.user表仅有password_last_changed,与登录行为无关。

确认账号登录时间字段是否存在且可查
MySQL本身不记录用户登录时间,所谓“僵尸账号”必须依赖你自己的业务表(比如 user_login_log 或 admin_user 中的 last_login_at 字段)。如果没存这个字段,直接查 MySQL 系统库的 mysql.user 表是无效的——它只有 password_last_changed,和登录行为无关。
常见错误现象:SELECT user FROM mysql.user WHERE last_login_at 报错或返回空,因为 <code>last_login_at 根本不存在。
- 先执行
DESCRIBE your_user_table;确认有类似last_login_time、updated_at或login_at的时间字段 - 若字段是字符串类型(如
VARCHAR),需用STR_TO_DATE()转换,否则比较会出错 - 注意时区:确保你的应用写入时间和查询时使用的时区一致,否则 30 天可能偏差数小时
构造“未登录”逻辑的正确 SQL 写法
“过去30天未登录”不是简单查 last_login_at 就完事。关键要区分三类账号:
- 从没登录过的(
last_login_at IS NULL) - 最后一次登录在30天前(
last_login_at ) - 登录字段被误设为未来时间(如初始化填了
'2099-01-01'),这种也要排除
推荐写法:
SELECT id, username, last_login_at FROM your_user_table WHERE last_login_at < DATE_SUB(NOW(), INTERVAL 30 DAY) OR last_login_at IS NULL OR last_login_at > NOW();
注意:OR last_login_at > NOW() 是防脏数据的兜底项,上线前建议先 SELECT COUNT(*) FROM ... WHERE last_login_at > NOW() 看看有没有异常值。
关联登录日志表时避免漏查和重复
如果你把登录记录单独存在 login_log 表里(更合理的设计),就不能只查用户主表,得用 LEFT JOIN 找“没有最近登录记录”的账号。
典型错误写法:SELECT u.* FROM users u WHERE u.id NOT IN (SELECT user_id FROM login_log WHERE login_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)) —— NOT IN 遇到 NULL 直接整个条件失效,结果为空。
正确做法(用 LEFT JOIN + IS NULL):
SELECT u.id, u.username
FROM users u
LEFT JOIN (
SELECT DISTINCT user_id
FROM login_log
WHERE login_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
) l ON u.id = l.user_id
WHERE l.user_id IS NULL;-
DISTINCT防止一个用户多次登录导致重复匹配 - 务必给
login_log.login_time加索引,否则 JOIN 会极慢 - 如果
login_log表巨大,先加条件限制扫描范围,比如WHERE login_time >= DATE_SUB(NOW(), INTERVAL 90 DAY)再过滤
权限账号识别:别只盯着 username
“僵尸权限账号”重点在“有权限但长期不用”,所以不能只筛普通用户。你需要结合权限模型判断哪些账号具备敏感操作能力:
- 查
role表中role_name IN ('admin', 'superuser', 'ops')的用户 - 或查权限中间表:
SELECT u.* FROM users u JOIN user_role ur ON u.id = ur.user_id WHERE ur.role_id IN (SELECT id FROM role WHERE permission_level >= 10) - 如果用 RBAC,还要排除已软删除的账号(
status != 'active')
最终建议把权限筛选和登录时间筛选合并成一步,而不是分两次查再人工比对——容易漏掉刚被赋权但还没登录的新权限账号。
真正难的不是 SQL 写法,而是厘清“谁算权限账号”——这取决于你们系统里的角色定义、权限粒度和是否支持动态授权。字段含义模糊时,宁可多问后端同事一句,也别靠猜。


















