公用用户存在于整个cdb(含cdb$root及所有pdb),必须在cdb$root中以c##开头创建,权限需显式指定container=all才跨容器生效;本地用户仅限单个pdb,命名和创建均受容器限制,对象与权限严格隔离。
本地用户只能在单个 pdb 内存在和使用,公用用户(common user)则贯穿整个 cdb,包括 cdb$root 和所有 pdb —— 这不是权限大小的问题,而是存在范围与生命周期的根本差异。
创建位置和语法强制约束
公用用户必须在 CDB$ROOT 容器中创建,且用户名必须以 c## 或 C## 开头(由 common_user_prefix 参数控制,默认不可省略);否则会报 ORA-65096: invalid common user or role name。
本地用户只能在某个已打开的 PDB 中创建,且不能以 c## 开头;否则触发 ORA-65094: invalid local user or role name。
-
create user c##admin identified by pwd;→ 只能在CDB$ROOT执行,成功后该用户自动“出现”在所有 PDB(即使未打开,也会延后创建) -
create user appuser identified by pwd;→ 必须先alter session set container=pdb1;,且仅存在于pdb1 - 试图在 PDB 中创建
c##xxx用户,或在 CDB$ROOT 中创建不带前缀的用户,都会被 Oracle 立即拒绝
权限作用域完全隔离
在 CDB$ROOT 中给公用用户授予的权限(如 DBA、CREATE SESSION),默认只在 CDB$ROOT 生效;它不会自动同步到任何 PDB —— 即使用户存在,也可能是“空权限”状态。
同理,在某个 PDB 中给同一公用用户(如 c##admin)授的权限,只对该 PDB 有效,其它 PDB 不继承。
-
GRANT CREATE SESSION TO c##admin CONTAINER=ALL;→ 显式指定才生效于所有容器 -
GRANT SELECT ANY TABLE TO c##admin;(未指定CONTAINER)→ 仅在当前容器(CDB$ROOT)生效 - 本地用户授的权限天然只对本 PDB 有效,无需也不支持
CONTAINER子句
对象归属与跨容器可见性
公用用户创建的对象(如表、视图)默认属于 CDB 公共对象空间,但只有显式声明为 SHARED(如使用 CREATE PLUGGABLE DATABASE ... SHARING=DATA 场景)才可能被多个 PDB 共享;绝大多数情况下,其对象仍按容器隔离。
本地用户创建的对象严格绑定在其所属 PDB 的数据字典中,CDB$ROOT 和其它 PDB 根本看不到这些对象,哪怕用 SELECT * FROM cdb_tables 查询也不会出现。
- 查询用户存在范围:用
SELECT username, common, con_id FROM cdb_users WHERE username = 'C##ADMIN';,common='YES'表示是公用用户,con_id=1是 CDB$ROOT,其它con_id对应各 PDB - 查本地用户:必须连入对应 PDB 后执行
SELECT username FROM dba_users;,cdb_users视图里只会显示con_id为其所在 PDB 的那一行 - 误以为“公用用户能跨 PDB 访问本地对象”是常见误解——它需要显式授权 + 对象名限定(如
pdb1.appuser.t1),且前提是该 PDB 已开放连接并赋权
最易被忽略的是:PDB 关闭时,公用用户的元数据仍保留在 CDB$ROOT,但其在该 PDB 的 schema 对象和权限处于“不可达”状态;重启 PDB 后需确认对象是否完整、权限是否仍有效——Oracle 不保证 PDB 插拔过程中的权限一致性,尤其是通过脚本批量授予权限后未验证各 PDB 实际状态。











