在PDB中直接授予COMMON ROLE(如DBA)会报ORA-65094,因其仅允许在CDB$ROOT中授给COMMON USER;正确做法是在CDB$ROOT执行GRANT DBA TO c##user CONTAINER=ALL,或在PDB内创建并授权LOCAL ROLE。

在PDB中直接GRANT Common Role会报ORA-65094
Oracle 12c+的多租户架构下,COMMON ROLE(如CONNECT、RESOURCE、DBA)默认只允许在CDB$ROOT中授予,且只能授给COMMON USER(即带C##前缀的用户)。如果你在PDB里执行GRANT DBA TO hr;,会立刻触发错误:ORA-65094: invalid local user or role name——不是用户名错了,而是DBA这个角色本身是common角色,不能跨容器“向下”授予本地用户。
必须先确认角色是否为COMMON ROLE
别凭名字猜。有些角色看起来像内置角色,实则是你或应用自己建的local角色。查清本质再操作:
- 在CDB$ROOT中运行:
SELECT ROLE, ORIGIN_CON_ID, COMMON FROM DBA_ROLES WHERE ROLE = 'DBA';—— 若COMMON = 'YES',说明它是common角色 - 在PDB中查不到该角色(
SELECT * FROM DBA_ROLES WHERE ROLE = 'DBA';返回空),也印证它不属于本PDB -
SELECT * FROM CDB_ROLES WHERE ROLE = 'DBA';可在CDB$ROOT中看到它在所有容器注册,但CON_ID列值为1(CDB$ROOT)才表示它“存在于此”,其他PDB的CON_ID只是元数据映射,不支持直接授权
正确做法:用CONTAINER=ALL在CDB$ROOT中授予COMMON USER
想让某个用户在所有PDB中都拥有DBA权限,唯一合规路径是:
- 以
SYS或具备GRANT ANY ROLE权限的COMMON USER身份,连入CDB$ROOT - 确保目标用户是
COMMON USER(用户名以C##开头,且创建时显式指定CONTAINER=ALL) - 执行:
GRANT DBA TO C##admin CONTAINER=ALL; - 注意:
CONTAINER=ALL必须写,否则默认只在当前容器(CDB$ROOT)生效;SET ROLE DBA;仍需在每个PDB内手动启用(因DEFAULT ROLE对common角色在PDB中不自动继承)
如果只是想让本地用户在单个PDB有DBA级权限
那就别碰common角色。直接在目标PDB内创建local role并赋权更安全、更可控:
- 先切到PDB:
ALTER SESSION SET CONTAINER = hrpdb; - 建local角色:
CREATE ROLE hr_dba; - 逐条授予权限(别直接
GRANT DBA):GRANT CREATE SESSION, CREATE TABLE, UNLIMITED TABLESPACE, SELECT ANY DICTIONARY TO hr_dba; - 再把角色给本地用户:
GRANT hr_dba TO hr; - 关键点:
UNLIMITED TABLESPACE必须显式授予,否则建表会报ORA-01950;SELECT ANY DICTIONARY替代了DBA里大部分数据字典访问需求,但不会开放DROP USER这类高危权限
绕过common role限制的本质,是放弃“一套角色打遍所有PDB”的幻想——PDB的隔离性决定了权限边界必须落在容器内部。强行跨容器授权,要么失败,要么埋下越权隐患。


















