SESSIONS_PER_USER仅限制已认证的数据库会话数,非TCP连接或连接池空闲连接;必须开启RESOURCE_LIMIT=TRUE、显式绑定PROFILE且防范INACTIVE会话残留才能生效。
不能直接限制“连接数”,只能限制数据库会话(session)数;sessions_per_user 是唯一原生机制,但必须配合 resource_limit=true 才生效。
为什么 SESSIONS_PER_USER 不等于“并发连接数”
它只统计 v$session 中 USERNAME 相同且 STATUS 为 ACTIVE 或 INACTIVE 的行——也就是已认证成功、尚未断开的数据库会话。TCP 连接、连接池空闲连接、监听器排队、登录失败重试都不计入。常见误判是看到应用报 ORA-02391 就以为是网络层堵了,其实说明认证已通过,只是会话数超限。
典型陷阱:
- 应用用 HikariCP 或 UCP 池化连接,配置了 20 个最大空闲连接 → 一启动就占满
SESSIONS_PER_USER限额 - DBA 忘记开
RESOURCE_LIMIT, PROFILE 配了也白配 - 用户已有 8 个活跃会话,你把限额从 10 改成 5 → 不踢人,只拦新登录
必须执行的三步硬性操作
缺一不可,顺序不能错:
- 检查并开启实例级开关:
SHOW PARAMETER resource_limit;若返回FALSE,执行ALTER SYSTEM SET resource_limit = TRUE SCOPE = BOTH - 新建或修改 PROFILE:
CREATE PROFILE app_limit LIMIT SESSIONS_PER_USER 3(注意大小写不敏感,但官方文档建议大写) - 绑定用户:
ALTER USER app_user PROFILE app_limit(不能直接ALTER USER ... LIMIT SESSIONS_PER_USER)
验证是否生效:SELECT LIMIT FROM DBA_PROFILES WHERE PROFILE = 'APP_LIMIT' AND RESOURCE_NAME = 'SESSIONS_PER_USER';查当前会话数:SELECT COUNT(*) FROM v$session WHERE USERNAME = 'APP_USER'。
连接池场景下容易踩的坑
多数报 ORA-02391 的真实原因是连接泄漏或池配置失当,不是数据库限制太严:
- HikariCP 的
maximumPoolSize建议 ≤SESSIONS_PER_USER值,否则启动即满 - UCP 需确认
connectionPool.setMinPoolSize(0),避免预热时占满限额 - 应用未正确调用
Connection.close(),导致会话长期INACTIVE却不释放 - 中间件(如 WebLogic)自身维护连接池,可能叠加多层会话,需统一协调限额
监控建议:定期查 SELECT SID, SERIAL#, STATUS, LOGON_TIME FROM v$session WHERE USERNAME = 'APP_USER' ORDER BY LOGON_TIME,识别长时间 INACTIVE 会话。
没有动态限流,也没有按 IP 或服务名区分
SESSIONS_PER_USER 是静态、粗粒度的控制。它无法做到:
- 根据客户端 IP 动态调整限额
- 对不同
SERVICE_NAME(比如APPvsREPORT)设置不同上限 - 在达到阈值前自动降级或排队,只会硬拒绝新登录
如果真需要这些能力,得绕过 PROFILE:用 Logon Trigger + 自定义表记录 IP/Service/Session 数,再抛异常拦截;或用 Database Resource Manager 分配 CPU/IO 资源间接抑制高并发影响。但这两种方案运维成本高,且 Logon Trigger 在 RAC 环境下需额外处理全局状态同步。
真正关键的点从来不是“怎么设限额”,而是“为什么这个用户会持续占用那么多会话”——先查 v$session 和应用日志,再动 PROFILE。











