必须先ALTER SESSION SET CONTAINER=pdb_name切换容器再创建用户,否则默认在CDB$ROOT执行;PDB内用户需LOCAL创建、授本地权限、查DBA_*视图,删除前须确认容器。
如何在PDB中创建用户并避免CDB$ROOT误操作
直接在pdb里创建用户,必须先用alter session set container = pdb_name切换容器,否则create user默认在cdb$root执行,导致用户无法登录pdb。常见错误是连上cdb后没切容器就建用户,结果用户被创建在根容器,后续授权也全错位。
实操建议:
- 连接时明确指定PDB服务名:
sqlplus /@pdb_service_name,比手动ALTER SESSION更安全 - 检查当前容器:运行
SELECT SYS_CONTEXT('USERENV', 'CON_NAME') FROM DUAL确认是否在目标PDB - PDB内用户必须以
LOCAL身份创建(Oracle 12c默认行为),不能加CONTAINER=ALL——那会报错ORA-65094: invalid local user name
给PDB用户授哪些权限才真正生效
PDB层级的权限只能在本PDB内授予,且仅限于CREATE SESSION、CREATE TABLE等本地权限。任何带CONTAINER=ALL的授权语句(如GRANT CREATE TABLE TO u1 CONTAINER=ALL)在PDB中会直接报错ORA-65047: not allowed in a pluggable database。
关键点:
-
GRANT CONNECT, RESOURCE TO u1可以执行,但RESOURCE角色本身是CDB级预定义角色,在PDB中授予它只影响当前PDB的权限映射 - 不要试图在PDB中授予
DBA角色——该角色含大量CDB级系统权限,在PDB中不可用,会触发ORA-01917: user or role 'DBA' does not exist - 若需自定义权限集,建议在PDB中创建本地角色(
CREATE ROLE r_pdb_admin),再逐条授权,避免跨容器依赖
为什么PDB用户无法访问CDB公共对象
PDB用户默认看不到CDB$ROOT里的表(如CDB_USERS)、视图或同义词,哪怕被授予了SELECT_CATALOG_ROLE。这是因为数据字典视图在多租户下做了容器隔离:CDB_*视图只对CDB管理员(SYS连CDB$ROOT)可见,PDB用户查CDB_USERS会返回空或报ORA-00942: table or view does not exist。
正确做法:
- PDB内应使用
DBA_*视图(如DBA_USERS)查本PDB对象 - 如果真需跨容器查信息,必须由CDB管理员在CDB$ROOT中创建公共同义词+授予
SELECT,且目标用户需有SET CONTAINER权限(极少开放) - 注意
SELECT_CATALOG_ROLE在PDB中只赋予对DBA_*视图的访问权,不是CDB_*
删除PDB用户时要注意什么
在PDB中执行DROP USER u1 CASCADE是安全的,但若误在CDB$ROOT执行,会删掉所有PDB里同名的本地用户(Oracle 12.2+默认行为),造成多个PDB同时失联。
防御性操作:
- 删除前必查容器:
SELECT CON_ID, USERNAME FROM CDB_USERS WHERE USERNAME = 'U1'—— 如果返回多行,说明是公共用户;如果只在某PDB的CON_ID下存在,才是本地用户 - 确保当前会话容器是目标PDB:
SHOW CON_NAME,再执行DROP USER - 不要依赖
ORACLE_SID判断环境,而要用服务名连接,因为SID可能指向CDB,服务名才能精准路由到PDB
多租户下的用户管理核心就一条:容器边界不可逾越。所有SQL执行前,先确认CON_NAME,比写一百行授权脚本都重要。











