Skip to content

pg_dump fails with 'query would be affected by row-level security policy'

Last edited: 10/14/2026

当你以自己创建的角色运行 pg_dump 时,导出会在第一个使用行级安全性的表处停止:

🌐 When you run pg_dump as a role you created, the export stops at the first table that uses Row Level Security:

pg_dump: error: query would be affected by row-level security policy for table "orders"

pg_dump 会关闭其会话的行级安全性,因此它要么导出表中的每一行,要么一行都不导出。没有 bypassrls 属性的角色无法读取每一行,因此导出会失败。更多信息,请参见 Postgres 关于 pg_dump 的文档。

创建一个备用角色 #

🌐 Create a backup role

创建一个专门的角色,可以在没有 postgres 密码的情况下读取每个表。在 SQL 编辑器 中运行以下内容:

🌐 Create a dedicated role that can read every table without the postgres password. Run the following in the SQL Editor:

create role backup_reader login password '<strong-password>' bypassrls;
grant pg_read_all_data to backup_reader;
alter role backup_reader set default_transaction_read_only = on;

每一条语句只做一件事:

🌐 Each statement does one job:

  • bypassrls 让 pg_dump 读取每一行。
  • pg_read_all_data 是一个预定义的 Postgres 角色。它让 backup_reader 能读取每个模式中的所有表、视图和序列,包括 auth 和 storage。
  • default_transaction_read_only 默认将角色的会话设置为只读,这可以防止意外写入。

pg_read_all_data 不支持大对象。如果你的数据库有大对象,完整导出会因 permission denied for large object 失败。

若要导出时不包含大对象,请在 pg_dump 命令中添加 --no-large-objects。在 pg_dump 15 及更早版本中,该选项是 --no-blobs。

🌐 To export without large objects, add --no-large-objects to the pg_dump command. In pg_dump 15 and earlier, the option is --no-blobs.

要包含大对象,给每个对象授予 select 给 backup_reader。只有大对象的所有者,或者对其拥有带授予权限的 select 角色,才能授予对它的访问权限。

🌐 To include large objects, grant select on each one to backup_reader. Only a large object's owner, or a role that holds select on it with the grant option, can grant access to it.

  1. 列出拥有大对象的角色:

    select distinct lomowner::regrole as owner from pg_largeobject_metadata;
  2. 以每个角色的身份运行以下代码块一次:

    do $$
    declare
    r record;
    begin
    for r in
    select oid from pg_largeobject_metadata
    where lomowner = current_user::regrole
    loop
    execute format('grant select on large object %s to backup_reader', r.oid);
    end loop;
    end
    $$;

要给你创建的另一个角色相同的访问权限,运行 alter role <role_name> bypassrls; 和 grant pg_read_all_data to <role_name>;。

运行导出 #

🌐 Run the export

  1. 打开 连接 面板,然后复制会话池或直接连接字符串。

  2. 在连接字符串中更改用户名,并删除密码。对于共享连接池,把 postgres.<project-ref> 改成 backup_reader.<project-ref>。对于直接连接,把 postgres 改成 backup_reader。

  3. 用连接字符串运行 pg_dump。使用与你的项目相同主要版本的 Postgres 的 pg_dump,或者更新的版本。

    pg_dump "postgresql://backup_reader.<project-ref>@<pooler-host>:5432/postgres" \
    --password \
    --file backup.sql

    --password 会提示输入密码。对于计划好的导出,省略 --password 并将密码存储在密码文件中。关于文件格式,请参阅 Postgres 文档中的 密码文件。

要导出特定的架构,为每个架构添加一个 --schema 选项,例如 --schema=public --schema=auth --schema=storage。使用 --schema 导出时会省略大对象。要包含它们,也需要添加 --large-objects,在 pg_dump 15 及更早版本中,它是 --blobs。

🌐 To export specific schemas, add a --schema option for each one, for example --schema=public --schema=auth --schema=storage. An export with --schema leaves out large objects. To include them, also add --large-objects, which is --blobs in pg_dump 15 and earlier.

直接运行 pg_dump 而不是 supabase db dump。Supabase CLI 命令在导出过程中会切换到 postgres 角色,所以对 backup_reader 会因为 permission denied to set role "postgres" 而失败。

🌐 Run pg_dump directly rather than supabase db dump. The Supabase CLI command switches to the postgres role during the export, so it fails for backup_reader with permission denied to set role "postgres".

导出只包含加密形式的 Vault 秘密,因为 backup_reader 无法解密它们。导出不包括角色密码。

🌐 The export contains Vault secrets in encrypted form only, because backup_reader can't decrypt them. The export doesn't include role passwords.

如果你的项目有一个 只读副本,你可以从副本导出数据,这样就不会增加主数据库的负担。要找到副本的连接字符串,在 连接 面板里将 源 设置为副本即可。只读副本是主数据库的一个副本,包括它的角色,所以 backup_reader 也可以用相同的密码连接到主数据库。

🌐 If your project has a Read Replica, you can export from the replica to keep the load off your Primary database. To find the replica's connection string, set Source to the replica in the Connect panel. A Read Replica is a copy of the Primary, including its roles, so backup_reader can also connect to the Primary with the same password.

备份角色还能做什么 #

🌐 What the backup role can still do

作为 backup_reader 的会话仍然可以通过这些方式写入:

🌐 A session as backup_reader can still write in these ways:

  • 会话可以运行 set default_transaction_read_only = off,因为这个设置是默认的。
  • 如果启用了 pg_net 扩展,Session 可以向 net.http_request_queue 添加行,pg_net 会将这些行作为 HTTP 请求发送。这个角色从 PUBLIC 获得了这个权限。
  • 该会话可以使用像 lo_create 这样的函数创建大对象,而 PUBLIC 可以运行它们。

要查看每个角色获得的所有权限列表,请参见 自定义角色继承未明确授予的权限。

🌐 For the full list of privileges every role receives, see Custom role inherits privileges that were not explicitly granted.

更换密码 #

🌐 Rotate the password

只在运行导出的系统中存储角色的密码。如果该系统被入侵了,记得更改密码:

🌐 Store the role's password only in the system that runs the export. If that system is compromised, change the password:

alter role backup_reader password '<new-strong-password>';

在更改密码后的大约15秒内,通过共享连接池的连接可能会失败,直到连接池获取到新的密码。

🌐 Connections through the shared pooler can fail for about 15 seconds after the change, until the pooler picks up the new password.

Supabase 每天都会为 Pro、Team 和 Enterprise 计划的项目进行备份,无需任何凭证。有关这些备份的更多信息,请参见 数据库备份。

🌐 Supabase backs up Pro, Team, and Enterprise Plan projects daily without any credentials. For more information about those backups, see Database Backups.