不能用read any table创建pdb本地只读用户,因其是cdb级权限,授出后可跨pdb查表,违背本地隔离原则;且不包含create session,用户无法登录目标pdb。

在 Oracle 19c 多租户环境中,**无法直接创建“PDB 本地只读用户”这种逻辑角色**——READ ANY TABLE 是 CDB 级系统权限,授予后用户可在所有已打开的 PDB 中查表(除非被限制),它本身不绑定到某个特定 PDB;而“只读用户”必须在目标 PDB 内显式创建并授权,且 CREATE SESSION 必须单独授予。
为什么不能用 READ ANY TABLE 创建“PDB 本地只读用户”
READ ANY TABLE 属于 CDB$ROOT 中的系统权限,一旦授予用户(如 GRANT READ ANY TABLE TO pdb_ro_user),该用户就能跨 PDB 查询任何可访问对象,与“本地”“限定于某 PDB”的需求矛盾。更重要的是:该权限不自动赋予登录能力,用户仍需在每个目标 PDB 中被显式授予 CREATE SESSION,否则连连接都进不去。
常见错误现象:
- 用户在 CDB$ROOT 被授
READ ANY TABLE,但连接目标 PDB 时报ORA-01045: user lacks CREATE SESSION privilege - 用户成功登录某 PDB 后能查
HR.EMP,却也能查SCOTT.DEPT(另一 PDB 的表),违反隔离预期 - 误以为
ALTER USER ... ACCOUNT LOCK可限制为“只读”,其实锁账户是禁用登录,和权限无关
正确做法:在目标 PDB 内创建最小权限只读用户
必须切换到目标 PDB 上下文(ALTER SESSION SET CONTAINER = pdb1)再操作,否则所有 DDL 都作用于 CDB$ROOT。
实操建议:
- 用具有
CREATE USER和SET CONTAINER权限的用户(如SYS)登录 CDB$ROOT - 执行
ALTER SESSION SET CONTAINER = pdb1切换上下文 - 运行
CREATE USER pdb_ro IDENTIFIED BY "Strong#123"—— 用户仅存在于当前 PDB - 立即授予
GRANT CREATE SESSION TO pdb_ro,否则无法连接 - 按需授只读权限:
GRANT SELECT ON hr.employees TO pdb_ro(对象级),或GRANT READ ON hr.employees TO pdb_ro(12c+ 推荐) - 如需对整个 schema 只读,可循环授
SELECT或用角色封装,但避免SELECT ANY TABLE(越权)
PDB 克隆后只读用户不会自动继承
克隆 PDB(如 CREATE PLUGGABLE DATABASE pdb2 FROM pdb1)时,源 PDB 中的本地用户(包括只读用户)及其权限会被完整复制到新 PDB,但前提是源 PDB 在克隆前处于 READ ONLY 模式(这是强制要求)。若源 PDB 是 READ WRITE,克隆会失败或产生不一致状态。
关键点:
- 克隆前必须执行
ALTER PLUGGABLE DATABASE pdb1 CLOSE IMMEDIATE→OPEN READ ONLY - 新 PDB(
pdb2)默认为MOUNTED状态,需手动ALTER PLUGGABLE DATABASE pdb2 OPEN READ WRITE才能使用 - 新 PDB 中的只读用户密码、权限、profile 完全继承自源 PDB,但其身份仍是“
pdb2本地用户”,与pdb1无关 - 若源 PDB 后续修改了该用户权限,不会同步到已克隆的 PDB
容易被忽略的权限边界问题
即使严格按 PDB 本地方式建用户,仍有两个隐蔽风险点:
-
SELECT权限不隐含对视图基表的访问权 —— 若用户有SELECTonhr.v_emp,但视图定义里用了scott.dept,而用户没被授scott.dept的SELECT,查询仍报错ORA-00942 - 数据字典视图(如
ALL_TABLES)默认对只读用户可见,但若想查DBA_TABLES,必须额外授SELECT CATALOG ROLE,该角色在 PDB 内有效但不可跨容器
真正安全的只读控制,依赖于“PDB 边界 + 显式对象授权 + 无通配权限”三者缺一不可。











