PostgreSQL 已给 public 授权仍无法建表:核对授权连接的数据库
同名 public 属于各自的数据库;比较管理员和应用的实际连接,在目标库给迁移角色授予需要的 schema 权限。
已经执行 GRANT USAGE, CREATE ON SCHEMA public,应用角色创建表仍报 permission denied for schema public,先核对授权会话连接的数据库。每个数据库都有自己的 schema;在 postgres 库里给 public 授权,不会改变 appdb 库里的同名 schema。
这在 PostgreSQL 15 及之后的新数据库中更容易遇到:默认的 public schema 不再向所有角色开放 CREATE。从旧版本升级的数据库可能保留旧权限,不能只凭服务器版本推断当前 ACL。以下以应用需要在 appdb.public 创建对象为例;名称都要换成实际值。
先比较两边连接到了哪里
在管理员的授权会话和应用实际使用的连接中,分别执行只读检查:
SELECT current_database(), current_user, session_user;
SHOW search_path;
SELECT has_schema_privilege(current_user, 'public', 'USAGE') AS can_use,
has_schema_privilege(current_user, 'public', 'CREATE') AS can_create;
第一行核对数据库与当前生效角色。连接池、迁移工具和终端可能用了不同的库名或角色;current_user 与登录身份不同,也可能是执行了 SET ROLE。最后一条查询只判断当前数据库的 public 权限。
如果管理员在 postgres,应用在 appdb,先切换授权会话,而不是重复扩大角色权限。在 psql 中可以使用:
\connect appdb
这是 psql 客户端命令,不能直接粘到其他工具的 SQL 编辑器。使用图形客户端时重新选择目标数据库,再通过 current_database() 确认;提示符或连接名称不一定足以判断。
如果两边数据库一致,但角色不同,检查应用真正的认证账号、角色切换与连接池配置。若报错名称是其他 schema,应检查那个 schema;不要把 public 当成所有目录的统称。
在目标库给需要建对象的角色授权
由 schema 所有者、持有相应 grant option 的角色或管理员,在已经确认的 appdb 中执行以下授权示例:
GRANT USAGE, CREATE ON SCHEMA public TO app_migrator;
USAGE 允许查找 schema 内的对象,CREATE 允许在那里创建对象。GRANT ALL ON DATABASE appdb 授予的是数据库层面的权限,不能代替这一步。它也不会自动授予已有表的读写权限或序列权限。
先记录现有授权与角色归属,只给确实负责迁移、建表的角色添加所需权限。普通应用运行账号如果只读写既有表,通常不需要 CREATE。允许不受信任的角色在公共搜索路径里创建对象会影响其他用户的查询,因此不应为排错向 PUBLIC 开放创建权限。
若需要撤回本次新增授权,先确认没有其他用途依赖它,再仅撤销本次添加的权限,例如:
REVOKE CREATE ON SCHEMA public FROM app_migrator;
不要同时撤销原来已有的 USAGE。角色还可能通过其他角色、所有权或其他授权路径保留权限;撤销一条直接授权不保证有效权限立即变为否。
用应用的真实连接确认结果
授权后回到应用所用数据库和角色,重复 has_schema_privilege 查询。需要建表时,can_create 应为真;原迁移操作应不再出现同一个 schema 权限错误。
如果下一步变成表或序列的 permission denied,说明已经进入另一层对象权限检查,应按具体对象处理。如果两项 schema 权限都为真却仍报错,继续核对报错时的连接、实际角色、schema 名和迁移工具是否使用了另一条连接。


