ora-02391报错源于sessions_per_user限制生效,但需resource_limit=true且profile正确绑定用户才起作用;它仅限制认证后的活跃/未断开会话,不控tcp连接或监听队列,连接池空闲会话会计入限额。

ORA-02391 不是连接没建上,而是认证成功后被拦在会话层——必须从 SESSIONS_PER_USER + RESOURCE_LIMIT + PROFILE 绑定三者协同入手,缺一不可。
为什么设置了 SESSIONS_PER_USER 却还报 ORA-02391
最常见原因是 RESOURCE_LIMIT 仍为 FALSE,导致所有 PROFILE 限制形同虚设。Oracle 不会主动提示这点,只默默忽略配置。
- 执行
SHOW PARAMETER resource_limit,确认返回值为TRUE;若为FALSE,必须先运行ALTER SYSTEM SET resource_limit = TRUE SCOPE = BOTH -
SESSIONS_PER_USER只统计v$session中USERNAME匹配且STATUS IN ('ACTIVE', 'INACTIVE')的行,TCP 连接、监听排队、登录失败重试都不计入 - 应用用 HikariCP 时,
maximumPoolSize = 20会导致一启动就占满限额,哪怕实际活跃 SQL 很少——这不是数据库太严,是池配置和限额没对齐 - 已有会话不受新限额影响,改完
ALTER PROFILE ... LIMIT SESSIONS_PER_USER 3后,当前 8 个会话仍存在,第 9 次新连接才报错
如何验证 SESSIONS_PER_USER 是否真正生效
不能只看 PROFILE 创建语句是否执行成功,要查两个地方:
- 查 PROFILE 实际绑定值:
SELECT LIMIT FROM DBA_PROFILES WHERE PROFILE = 'APP_LIMIT' AND RESOURCE_NAME = 'SESSIONS_PER_USER' - 查当前该用户真实会话数:
SELECT COUNT(*) FROM v$session WHERE USERNAME = 'APP_USER'(注意大小写敏感,用户名全大写) - 如果
DBA_PROFILES查不到值,说明 PROFILE 名写错或未生效;如果v$session计数远高于限额,说明连接泄漏或池未 close - 测试时别用
sqlplus / as sysdba,要用目标用户反复 connect,例如循环执行sqlplus app_user/pass@db直到第 N+1 次失败
连接池场景下怎么避免误触限制
HikariCP、UCP、Druid 等池化连接器维持的空闲连接,在 Oracle 看来就是合法 INACTIVE 会话,会持续占用 SESSIONS_PER_USER 额度。
- HikariCP 的
maximumPoolSize必须 ≤SESSIONS_PER_USER值,否则启动即满 - UCP 需显式设
connectionPool.setMinPoolSize(0),否则预热阶段会提前占满限额 - 确保应用代码中每个
Connection都被close()调用——未 close 的连接会让会话长期卡在INACTIVE状态 - WebLogic 等中间件自带连接池,若再套一层应用池,会话数叠加,需统一协调各层限额
为什么 PROFILE 的 IDLE_TIME 对挂起连接无效
IDLE_TIME 在连接池场景下基本不起作用:它只在专用服务器模式下、客户端断连后服务端尚未清理的“假空闲”状态触发,且仅当该会话下次发请求时才检查。
- 连接池维持的长空闲连接属于真
INACTIVE,IDLE_TIME完全不扫描也不中断 - RAC 环境中
IDLE_TIME不跨实例同步,无法统一管控 - 真正能自动清理挂起连接的是
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE中的max_idle_time参数,单位秒,必须设在具体 consumer group(如APP_USERS)上,不能设在OTHER_GROUPS - 例如:30 分钟无活动断开,需执行
max_idle_time => 1800,且该策略对新会话立即生效,旧会话等下次激活时检测
SESSIONS_PER_USER 是静态阈值,不是动态熔断;它不感知 IP、service_name 或连接来源,只认用户名。一旦配置失当,问题会藏在连接池预热、应用重启、批量任务并发等边界场景里,不容易复现,但爆发时很突然。











