create job系统权限必须直接授予创建job的用户,不能通过角色间接获得;还需检查调度器是否被全局禁用(scheduler_disabled)。
oracle 中 create job 权限到底要授给谁?
不是授给 job 本身,而是授给「创建 job 的用户」——也就是执行 dbms_scheduler.create_job 的那个数据库用户。如果用户没有 create job 系统权限,调用过程会直接报错:ora-27486: insufficient privileges。
常见错误是误以为只要有了 EXECUTE 权限在 DBMS_SCHEDULER 包上就够了,其实不够。这个包只是工具,真正控制 job 创建资格的是系统级权限。
-
CREATE JOB是系统权限,必须由 DBA 或具备ADMINISTER DATABASE TRIGGER的用户授予 - 普通用户不能靠角色(如
SCHEDULER_ADMIN)间接获得该权限——角色在定义 job 时不会被启用,必须显式授予直接权限 - 如果使用
DBMS_SCHEDULER.CREATE_JOB指定了job_style => 'LIGHTWEIGHT',仍需CREATE JOB;但若用'REGULAR'且 owner 不是当前用户,则还需目标 schema 的ALTER ANY JOB
为什么 GRANT CREATE JOB TO user_name 还是报错?
大概率是因为权限没生效,或者对象权限/角色干扰了判断。Oracle 在 scheduler job 创建过程中对权限检查非常严格,且不走常规角色路径。
典型现象:DBA 执行了授权,用户连上去立刻试,还是 ORA-27486。这时候别急着重授,先确认几件事:
- 用户是否在新会话中测试?权限不会自动加载到已存在的 session,必须重新连接
- 是否用了连接池或中间件(如 Tomcat + JDBC)?某些连接池复用旧 session,导致权限不可见
- 用户是否属于
CONNECT角色?老版本 Oracle 中CONNECT含CREATE JOB,但 12c+ 已移除,必须显式授 - 有没有触发器或安全策略(如 RLS、VPD)拦截了权限校验?极少见,但排查到最后值得看一眼
DBMS_SCHEDULER 的 job owner 和 privilege_level 怎么配才不出问题?
job 的 owner 决定它以谁的身份运行,而 privilege_level 参数(默认 'DEFINER')决定运行时能访问哪些对象。这两者配合不对,就会出现 job 跑成功但查不到数据、或中途报 ORA-01031: insufficient privileges。
最稳妥的组合是让 owner = 创建者,并保持 privilege_level => 'DEFINER'。一旦设成 'INVOKER',job 就按调用者权限跑——但 scheduler job 没有“调用者上下文”,这个值基本无效,还容易引发权限混乱。
- 不要把 job owner 设为其他用户(比如
SCOTT),除非你明确需要它以 SCOTT 身份访问 SCOTT 的表,且已给创建者ALTER ANY JOB和EXECUTE ANY PROCEDURE - 避免用
GRANT EXECUTE ON SYS.DBMS_SCHEDULER TO user_name——这不是必需的,EXECUTE_CATALOG_ROLE已包含,且显式授权 sys 包有安全风险 - 如果 job 要访问另一个 schema 的表,优先用 owner 自身的同义词或直接授权,而不是靠
privilege_level切换
Job 能创建但不运行?检查 DBA_SCHEDULER_GLOBAL_ATTRIBUTE 里的 'SCHEDULER_DISABLED'
这是最容易被忽略的全局开关。即使所有权限都对、job 状态是 ENABLED,如果调度器被全局禁用,job 就永远卡在 DISABLED 实际状态(DBA_SCHEDULER_JOBS.STATUS 显示 DISABLED,但 ENABLED 字段却是 TRUE)。
查法很简单:
SELECT * FROM DBA_SCHEDULER_GLOBAL_ATTRIBUTE WHERE ATTRIBUTE_NAME = 'SCHEDULER_DISABLED';
如果值是 TRUE,DBA 必须执行:
EXEC DBMS_SCHEDULER.SET_SCHEDULER_ATTRIBUTE('SCHEDULER_DISABLED','FALSE');
- 这个设置不需要重启实例,但影响所有 job,包括已存在的
- 有些高安全环境会默认关闭 scheduler,上线前务必确认,别只盯着用户权限打转
- 该属性不写入 spfile,实例重启后恢复默认值(
FALSE),所以如果是临时设为TRUE,得检查是否被脚本反复覆盖










