Oracle 23ai/26ai起,PDB本地用户可用ALTER USER ... READ ONLY实现会话级只读控制,禁写但保读、不改权限,需在目标PDB执行且查DBA_USERS.READ_ONLY确认状态。

直接用 ALTER USER ... READ ONLY 是最省事的方案
Oracle 23ai/26ai 起,PDB 本地用户支持原生命令级只读标记。它不依赖权限回收、不改角色、不碰对象授权,只要执行:ALTER USER app_user READ ONLY;,该用户后续所有会话就自动禁止写操作——INSERT、UPDATE、DELETE、CREATE TABLE 全部报 ORA-28194: Can perform read operations only,但 SELECT 照常执行,原有所有权限(包括 DBA 角色)依然保留在数据字典里。
关键点在于:这个开关是会话级生效的,且仅作用于被标记的 PDB 本地用户;CDB 公共用户、其他 PDB 用户、甚至同一 PDB 内未被标记的账号完全不受影响。
容易踩的坑:
- 误以为
READ ONLY是权限状态——其实它是运行时策略,查DBA_USERS.READ_ONLY字段才能确认当前是否启用 - 在 CDB$ROOT 下执行该语句会报错,必须连到目标 PDB 再操作
- 用户已存在且有密码过期策略时,
READ ONLY不会绕过密码验证,登录仍需有效凭证
批量授予指定 Schema 所有表的 SELECT 权限要避开 SELECT ANY TABLE
如果还在用 23ai 之前的老版本,或需要兼容更广的 Oracle 版本,就得走传统授权路径。但别直接授 SELECT ANY TABLE——它允许查所有 Schema 的所有表,权限过大,审计风险高,且无法限制到某一个业务 Schema。
正确做法是动态生成授权语句:
SELECT 'GRANT SELECT ON ' || owner || '.' || table_name || ' TO readonly_user;' FROM dba_tables WHERE owner = 'APP_SCHEMA' AND temporary = 'N';
执行结果粘贴后批量运行即可。注意两点:
-
dba_tables需 DBA 权限;若用all_tables,得确保当前用户有对应对象的SELECT权限,否则漏表 - 视图、同义词、物化视图等非表对象不会被包含,如需支持,得额外加
dba_views、dba_synonyms查询 - 表名含特殊字符(如双引号包裹)时,生成的语句可能语法错误,建议先过滤
object_name NOT LIKE '%"%'
同义词不是可选项,而是可用性刚需
只授 SELECT ON app_schema.t1 后,用户必须写 SELECT * FROM app_schema.t1 才能查——这对应用很不友好,尤其 ORM 或报表工具默认不带 Schema 前缀。
所以得配同义词:
CREATE OR REPLACE SYNONYM readonly_user.t1 FOR app_schema.t1;
同样推荐批量生成:
SELECT 'CREATE OR REPLACE SYNONYM readonly_user.' || table_name || ' FOR app_schema.' || table_name || ';' FROM dba_tables WHERE owner = 'APP_SCHEMA';
注意:
- 用户必须有
CREATE SYNONYM权限(不是CREATE PUBLIC SYNONYM,后者全局可见,不安全) - 同义词名不能和用户已有对象重名,否则创建失败;可加前缀如
app_t1规避 - 如果表后期增删,同义词不会自动同步,需重新跑脚本或加自动化任务
READ ONLY 用户连不上 Navicat / DBeaver?检查连接参数和对象可见性
很多用户反馈:明明授权成功,但在 GUI 工具里看不到任何表。常见原因不是权限问题,而是工具配置:
- Navicat 默认只显示“当前用户拥有的对象”,需手动切换 Schema 列表,选中源 Schema(如
APP_SCHEMA)才能看到表 - DBeaver 默认不展开其他 Schema,右键连接 → “编辑连接” → “初始化”页 → 勾选“连接时加载所有 Schema”
- PL/SQL Developer 必须在登录时选择 “All Users”,否则只列当前用户名下的对象
- 如果用了同义词,但工具没刷新缓存,尝试断开重连,或执行
SELECT * FROM USER_SYNONYMS;确认同义词已生效
真正难排查的是混合场景:用户既被设为 READ ONLY,又单独授了 SELECT 权限——此时写操作仍被拦截,但权限查询会显示“有权限”,容易误导。务必优先查 DBA_USERS.READ_ONLY 字段,再看授权视图。


















