ORA-28001错误本质是用户expiry_date已早于当前时间(如2026-05-12),必须由DBA执行ALTER USER IDENTIFIED BY重置密码以清除过期状态并恢复OPEN,仅解锁、改profile或重启均无效。

ORA-28001 错误只说明一件事:当前用户的 expiry_date 字段值已早于系统时间,必须由 DBA 执行 ALTER USER ... IDENTIFIED BY 显式重置密码才能恢复连接,其他操作(如解锁、改 profile、重启应用)全无效。
怎么确认真是密码过期,而不是连不上或配错了?
别猜,直接查 dba_users 视图。用 DBA 账户执行:
SELECT username, account_status, expiry_date, profile FROM dba_users WHERE username = 'YOUR_USER';
关键看三列:
-
account_status是EXPIRED或EXPIRED(GRACE)→ 确认过期 -
expiry_date是个过去的时间(比如2026-05-12 00:00:00),而今天是2026-09-29→ 根源坐实 -
profile字段告诉你策略在哪,但不等于策略改了用户就自动“复活”
为什么 ALTER USER ACCOUNT UNLOCK 不起作用?
因为 ACCOUNT UNLOCK 只处理锁定状态(LOCKED),不碰过期状态(EXPIRED)。Oracle 把这两件事分开存:一个字段管锁,一个字段管过期。常见错误操作:
- 只执行
ALTER USER your_user ACCOUNT UNLOCK;→ 状态仍为EXPIRED,登录失败 - 执行
ALTER USER your_user IDENTIFIED BY old_password;却报ORA-28007→ 密码历史策略阻止复用旧密码,不是操作错,是策略在生效 - 以为
ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED能“回滚”已过期 → 它只影响未来新建或尚未过期的用户,对expiry_date已写死的记录完全没反应
DBA 必须执行的修复命令和坑点
用 SYS 或其他有 DBA 角色的账户登录后,执行以下之一(推荐第一个):
-
ALTER USER your_user IDENTIFIED BY new_password;→ 最稳妥,自动清除expiry_date、解除锁定、状态变OPEN -
ALTER USER your_user PASSWORD EXPIRE;→ 不改密码,但强制下次登录时必须改密;适合灰度过渡,但本次连接仍失败 - 想保留原密码又绕过
ORA-28007?得用IDENTIFIED BY VALUES,需先从sys.user$查spare4值,操作重、易出错,一般不建议
注意:IDENTIFIED BY 本身就包含解锁逻辑,无需再补 ACCOUNT UNLOCK;服务账户改密后,必须立刻同步到所有配置项(K8s Secret、连接池配置、ETL 工具等),否则重启应用照样连不上。
Java 应用里捕获不到 ORA-28001?
不是你 catch 写得不对,而是 JDBC 在 DriverManager.getConnection() 阶段就认证失败,根本不会走到业务 SQL 执行环节。真正能稳定识别的方式是:
if (e instanceof SQLException) {
SQLException sqle = (SQLException) e;
if (sqle.getErrorCode() == 28001 || "72000".equals(sqle.getSQLState())) {
// 启动修复流程
}
}
靠 getMessage().contains("expired") 不可靠——NLS 语言环境一换就失效。更关键的是:即使代码识别成功,也必须满足三个硬前提才能自动修复:有独立高权管理连接、已预存密码哈希(或能提供新密)、连接池支持主动驱逐旧连接。缺一不可,否则改完密码,池里还在复用旧连接,照样报错。
最常被忽略的一点:expiry_date 是持久化字段,它不会随 profile 修改、数据库重启、甚至用户 ALTER USER 其他属性而自动更新。只要它写着过去的时间,用户就登不进去——哪怕你刚把 PASSWORD_LIFE_TIME 改成 UNLIMITED,也得手动执行一次 IDENTIFIED BY 才行。











