正确导出用户权限需用expdp CONTENT=METADATA_ONLY配合精准INCLUDE与EXCLUDE,或直接SQLFILE生成可读脚本;导入前须确保目标库存在依赖对象,普通用户需SELECT_CATALOG_ROLE等最小权限。
只导出用户权限,别碰表数据和对象结构
直接用 expdp 导出权限,核心是绕开表、索引、约束等实际对象,只抓元数据里的授权语句。默认 schemas=xxx 会连带导出该用户的全部对象(含数据),这不是你想要的。
正确做法是用 CONTENT=METADATA_ONLY + 精确 INCLUDE 列表,把权限相关对象类型全列出来,同时排除掉所有可能带出结构或数据的项:
-
INCLUDE=USER,ROLE,ROLE_GRANT,DEFAULT_ROLE,SYSTEM_GRANT,OBJECT_GRANT,TABLESPACE_QUOTA,PROFILE—— 这些覆盖了用户账号、角色定义、被授角色、系统权限(如CREATE SESSION)、对象权限(如GRANT SELECT ON hr.employees TO app_user)、配额、配置文件 - 必须显式加
EXCLUDE=TABLE,INDEX,CONSTRAINT,VIEW,PROCEDURE,FUNCTION,PACKAGE,SYNONYM,SEQUENCE,TRIGGER—— 否则哪怕没写SCHEMAS,某些版本仍可能因依赖关系捎带上部分对象定义 - 不加
SCHEMAS或FULL=Y,否则范围失控;如果只想导特定用户,用INCLUDE=SCHEMA:"IN ('APP_USER')"替代SCHEMAS
生成可读 SQL 脚本,而不是二进制 .dmp 文件
如果你要的是能人工审核、编辑、分发的 SQL 文本(比如给 DBA 审批,或做跨版本适配),别用 DUMPFILE,改用 SQLFILE:
运行命令:expdp '/ as sysdba' INCLUDE=USER,SYSTEM_GRANT,OBJECT_GRANT,ROLE_GRANT DIRECTORY=DATA_PUMP_DIR SQLFILE=user_grants.sql LOGFILE=sqlfile_gen.log
这个命令不会生成 .dmp,而是在 DATA_PUMP_DIR 下输出一个纯文本 user_grants.sql,里面全是 CREATE USER、GRANT ... TO ...、ALTER USER ... QUOTA ... 这类语句。
注意点:
-
SQLFILE会忽略EXCLUDE,所以INCLUDE必须足够精准,否则脚本里混入不想要的语句 - 密码哈希值(
IDENTIFIED BY VALUES)会被写出,但不会还原明文密码;若目标库需统一密码策略,得后续手工替换 - 脚本中不含
CREATE ROLE,除非你显式加了INCLUDE=ROLE;角色缺失会导致GRANT my_role TO user在目标库执行失败
导入时权限静默失效?先检查 base object 是否存在
用 impdp 导入权限脚本或元数据 dump 后,发现用户连得上但查不了表,日志里只有 ORA-39112: Dependent object type GRANT:"HR" skipped, base object type TABLE:"SCOTT"."EMP" not created —— 这不是报错,是警告,而且默认被跳过。
根本原因:权限依赖的对象(如表、视图、角色)在目标库不存在,impdp 不会自动创建它们,只会跳过对应 GRANT。
解决路径很明确:
- 导入前,确保目标库已有对应 schema 用户(
CREATE USER)、角色(CREATE ROLE)、以及所有被授权的对象(表/视图等)。可以用SELECT owner, object_name, object_type FROM dba_objects WHERE owner IN ('SCOTT')核对 - 不要依赖
REMAP_SCHEMA自动修正权限语句里的对象名,它只改TO部分(被授权方),不改ON scott.emp这种FROM部分;如果源库是scott.emp,目标库实际是hr.emp,得手动改 SQLFILE 或用REMAP_SCHEMA=scott:hr配合INCLUDE=OBJECT_GRANT,但仍有局限 -
GRANTS=YES是默认值,不用显式写;真正影响是否跳过的,是 base object 是否已存在,不是这个参数
最小权限组合:让普通用户也能导出自身权限
非 DBA 用户想导自己账号的权限(比如审计自查、迁移准备),不需要 EXP_FULL_DATABASE 那种高危权限。
只需三步授权:
-
GRANT CREATE SESSION TO myuser—— 登录基础 -
GRANT SELECT_CATALOG_ROLE TO myuser—— 查数据字典视图(DBA_TAB_PRIVS、DBA_SYS_PRIVS等),这是读取权限元数据的前提 -
GRANT READ ON DIRECTORY dp_dir TO myuser—— 目录读写权限(注意:必须是READ和WRITE,只给READ无法导出)
然后执行:expdp myuser/mypwd DIRECTORY=dp_dir DUMPFILE=self_privs.dmp CONTENT=METADATA_ONLY INCLUDE=USER,SYSTEM_GRANT,OBJECT_GRANT LOGFILE=self_privs.log
这里的关键是:普通用户无法查其他用户的权限,所以 SELECT_CATALOG_ROLE 只能拿到自己有访问权的对象权限(即自己被授予的权限),但足以满足“导出自身权限”这个场景。如果漏了 SELECT_CATALOG_ROLE,expdp 会报 ORA-31631: privileges are required,即使你已经给了 CREATE SESSION。
最后提醒一句:SQLFILE 输出的脚本里,GRANT 语句顺序是有依赖的——先 CREATE ROLE,再 GRANT 角色,最后 GRANT 给用户。人工调整时别颠倒,否则执行报错。


















