应查询dba_users中account_status非'open'和'expired(grace)'的所有用户,按lock_date降序排列,并以account_status字符串为准判断锁定状态,lock_date仅作辅助参考。

直接查 DBA_USERS 视图就能拿到账号状态和锁定时间,但只看 account_status 等于 'LOCKED' 会漏掉真正卡住连接的用户——比如 'LOCKED(TIMED)' 或 'EXPIRED & LOCKED' 这类组合状态,它们一样无法登录。
查所有非正常状态用户,别只盯 LOCKED
Oracle 的“被锁”不是单一值,而是多种字符串组合。只过滤 'LOCKED' 会忽略大量实际不可用的账户。
-
account_status IN ('LOCKED', 'LOCKED(TIMED)', 'EXPIRED & LOCKED', 'EXPIRED(GRACE) & LOCKED')才覆盖全部真实锁定态 -
EXPIRED(GRACE)是宽限期,用户还能登录改密,不用立即处理 - 加
ORDER BY lock_date DESC能快速定位最新异常,比翻全表高效得多 - 带上
profile字段,后续可直接关联DBA_PROFILES查FAILED_LOGIN_ATTEMPTS设置
推荐语句:
SELECT username, account_status, lock_date, expiry_date, profile FROM dba_users WHERE account_status NOT IN ('OPEN', 'EXPIRED(GRACE)') ORDER BY lock_date DESC;
LOCK_DATE 为空 ≠ 没被锁
看到 lock_date IS NULL 就以为账号没锁,是常见误判。Oracle 在某些场景下根本不写这个字段,哪怕状态已是 'LOCKED(TIMED)' 或 'EXPIRED & LOCKED'。
-
LOCKED:手动锁的,lock_date通常有值(旧版本 Bug 9693615 可能导致为 NULL) -
LOCKED(TIMED):输错密码触发的,lock_date多数有值,但补丁缺失版本可能为 NULL -
EXPIRED & LOCKED:密码过期后又输错一次,状态变了,lock_date却不更新——这是 Oracle 已知行为,不是你的 SQL 写错了
结论:永远以 account_status 字符串为准,lock_date 只作辅助参考。
ADG 备库上查不到最新状态?小心同步延迟
在 Oracle ADG 环境下,DBA_USERS 在备库上不是实时的。主库刚 UNLOCK 完,切到备库立刻查,account_status 还可能是旧值。
- 先确认是否 ADG:
SELECT database_role FROM v$database,返回PHYSICAL STANDBY就是备库 - 查日志应用进度:
SELECT max(sequence#) FROM v$archived_log WHERE applied='YES',对比主备归档号差值 - 备库上别靠
DBA_USERS判断能否登录,真实连接测试或查v$session_connect_info更可靠
真正麻烦的不是查不到,而是查到了却误判——比如把 LOCKED(TIMED) 当成临时状态放着不管,结果发现背后有应用在持续用错误密码重连;或者在备库上看到 OPEN 就认为没问题,实际主库早已锁死。状态字段是字符串,不是布尔值,得逐字比对,不能靠直觉。











