dbms_metadata.get_granted_ddl不能备份用户完整权限,仅导出对象级授权;系统权限、角色授予、密码策略等需通过dba_sys_privs、dba_role_privs等数据字典视图组合查询生成脚本。
不能直接用 dbms_metadata.get_granted_ddl 备份“用户权限配置”——它只导出对象级授权语句,不包含系统权限、角色授予、密码策略等关键项。
DBMS_METADATA.GET_GRANTED_DDL 只返回对象权限,不是完整权限快照
这个函数常被误认为能导出用户全部权限,实际它只处理对象权限(比如 SELECT、INSERT 某张表),且必须指定具体对象类型和名称。系统权限(如 CREATE SESSION)、角色授予(GRANT DBA TO user1)、默认表空间、临时表空间、密码限制等,它一概不返回。
- 调用示例:
SELECT DBMS_METADATA.GET_GRANTED_DDL('TABLE', 'EMP', 'SCOTT') FROM DUAL;—— 仅输出 SCOTT 对 EMP 表的GRANT语句 - 对系统权限无效:执行
DBMS_METADATA.GET_GRANTED_DDL('SYSTEM_GRANT', ...)会报错ORA-31600: invalid object type SYSTEM_GRANT - 无法批量导出:不支持 “所有对象权限 for user1”,必须逐个对象调用
真正能备份用户权限全貌的,是数据字典查询组合
要还原一个用户的完整权限上下文(含登录能力、角色、系统权限、对象权限、密码属性),必须查多个视图并拼接 SQL:
- 系统权限:
SELECT * FROM DBA_SYS_PRIVS WHERE GRANTEE = 'USER1'; - 角色授予:
SELECT * FROM DBA_ROLE_PRIVS WHERE GRANTEE = 'USER1'; - 对象权限:
SELECT * FROM DBA_TAB_PRIVS WHERE GRANTEE = 'USER1';(注意不含列级权限,需额外查DBA_COL_PRIVS) - 用户基础属性:
SELECT USERNAME, DEFAULT_TABLESPACE, TEMPORARY_TABLESPACE, ACCOUNT_STATUS, EXPIRY_DATE FROM DBA_USERS WHERE USERNAME = 'USER1'; - 密码策略(如适用):
SELECT * FROM DBA_PROFILES WHERE PROFILE IN (SELECT PROFILE FROM DBA_USERS WHERE USERNAME = 'USER1');
这些结果需人工或脚本转成可执行的 GRANT/CREATE USER 语句——没有单条函数能替代。
RMAN 和 expdp 都不保存权限元数据,别指望它们
有人想用 RMAN 物理备份或 expdp 逻辑导出“顺便带走权限”,这是误区:
- RMAN 备份的是数据文件、控制文件、归档日志,权限信息存在数据字典表里,但恢复后用户仍需显式授权才能使用——RMAN 不重建授权关系
-
expdp默认不导出用户定义(INCLUDE=USER才导),且即使导出,也只含CREATE USER和对象权限(通过GRANTS=Y),仍缺失系统权限和角色继承链 - 常见错误:
expdp system/... schemas=SCOTT include=grant看似导出了权限,但GRANT CONNECT TO SCOTT这类语句可能被跳过,因为 CONNECT 是角色,不是对象权限
最实用的权限备份方案:SQL 脚本 + 定期导出
与其依赖某个函数,不如写一段可复用的查询脚本,生成完整的重建语句:
SELECT 'CREATE USER ' || USERNAME || ' IDENTIFIED BY VALUES ''' || PASSWORD || ''' DEFAULT TABLESPACE ' || DEFAULT_TABLESPACE || ' TEMPORARY TABLESPACE ' || TEMPORARY_TABLESPACE || ';' FROM DBA_USERS WHERE USERNAME = 'USER1' UNION ALL SELECT 'GRANT ' || PRIVILEGE || ' TO ' || GRANTEE || DECODE(ADMIN_OPTION, 'YES', ' WITH ADMIN OPTION;') FROM DBA_SYS_PRIVS WHERE GRANTEE = 'USER1' UNION ALL SELECT 'GRANT ' || GRANTED_ROLE || ' TO ' || GRANTEE || DECODE(ADMIN_OPTION, 'YES', ' WITH ADMIN OPTION;') FROM DBA_ROLE_PRIVS WHERE GRANTEE = 'USER1';
注意三点:
- 密码哈希值(
PASSWORD列)在 12c 中默认不可见,需用DBA_USERS.PASSWORD_VERSIONS和密码文件验证方式判断是否能复用;更稳妥做法是导出时重置密码并记录 - 脚本不处理细粒度访问控制(FGAC)、标签安全策略(OLS)、应用上下文等高级权限,这些需单独检查
DBA_POLICIES、DBA_SA_POLICIES - 若用户属于 PDB,在 CDB$ROOT 中查不到其对象权限,必须先
ALTER SESSION SET CONTAINER = pdb_name;再执行查询
权限不是静态快照,而是运行时动态生效的规则集合。任何“备份”都只是某一时点的策略快照,真正难的是理解哪些权限被隐式继承、哪些被角色覆盖、哪些被细粒度策略拦截——这些靠一行函数根本覆盖不了。











