跨Container授予权限必须在CDB$ROOT中对公共用户/角色显式使用CONTAINER=ALL;本地用户无法跨PDB授权,且授权后须逐个PDB验证生效。
跨 container 授予权限在 oracle 12c 多租户环境中不是“自动生效”的操作,必须显式指定 container=all,且仅对公共用户(c## 前缀)和公共角色有效;本地用户、本地角色无法跨 pdb 生效。
GRANT 必须带 CONTAINER=ALL 才能跨 PDB
在 CDB$ROOT 中执行 GRANT 时,不加 CONTAINER 子句默认只作用于当前容器(即 CDB$ROOT),哪怕被授权对象是公共用户。这是最常踩的坑。
-
GRANT CREATE SESSION TO c##user1;→ 仅在 CDB$ROOT 生效,PDB 中仍报ORA-01045: user lacks CREATE SESSION privilege -
GRANT CREATE SESSION TO c##user1 CONTAINER=ALL;→ 在所有已打开且含该用户的 PDB 中生效(包括未来新建的 PDB) -
CONTAINER=ALL要求授权者当前连接在 CDB$ROOT,且必须是 common user(如SYS或带c##前缀的管理员) - 若 PDB 未 open,授权会跳过该 PDB;待其 open 后无需重授,权限自动可用
只能对公共用户/角色跨 Container 授权
本地用户(在 PDB 内创建、无 c## 前缀)根本不能出现在 CDB$ROOT 的 DBA_USERS 或 CDB_USERS 中,因此无法在 root 中对其执行 GRANT ... CONTAINER=ALL —— 语句直接报 ORA-01917: user or role 'xxx' does not exist。
- 公共用户:用户名以
c##(或自定义common_user_prefix)开头,存在于CDB_USERS中,COMMON='YES' - 本地用户:只存在于对应 PDB 的
DBA_USERS,COMMON='NO',只能在该 PDB 内用CONTAINER=CURRENT(或省略)授权 - 试图对本地用户执行
GRANT ... CONTAINER=ALL会失败,语法允许但逻辑不成立
角色授权也需区分 CONTAINER=ALL 和 CONTAINER=CURRENT
角色本身有“公共”和“本地”之分,但授权行为是否跨容器,取决于 GRANT 语句中的 CONTAINER 子句,而非角色类型。
- 用
CREATE ROLE c##role1 CONTAINER=ALL;创建的公共角色,仍需用GRANT c##role1 TO c##user1 CONTAINER=ALL;才能让该角色在所有 PDB 中激活 - 若写成
GRANT c##role1 TO c##user1;(无子句),则角色只在 CDB$ROOT 中被授予,PDB 中c##user1无法使用该角色下的权限 - 本地角色(
CREATE ROLE pdbrole;)只能在创建它的 PDB 中被授予,CONTAINER=ALL对其无效,会报错
验证跨 Container 授权是否真正生效
不能只查 CDB_ROLE_PRIVS 或 CDB_SYS_PRIVS 就认为 OK —— 这些视图只反映“授权记录”,不保证运行时可用。必须实际连接目标 PDB 验证。
- 先确认用户在目标 PDB 中存在:
SELECT username, con_id FROM cdb_users WHERE username = 'C##USER1' AND con_id = <pdb_con_id>; - 再切换到该 PDB:
ALTER SESSION SET CONTAINER = mypdb; - 用该用户登录:
CONN c##user1/password@mypdb,看是否成功 - 执行依赖权限的操作,例如
SELECT * FROM scott.emp;,避免只验CREATE SESSION而漏掉SELECT ANY TABLE等后续权限
跨 Container 授权的关键不在“能不能”,而在“在哪连、对谁授、怎么写”。少一个 CONTAINER=ALL,或连错容器(比如在 PDB 里执行全局授权),权限就只躺在 CDB$ROOT 里不动。真实环境里,PDB 数量一多,漏授或误授几乎必然发生,务必逐个 PDB 登录验证。


















