墨天轮主页:https://www.modb.pro/db/2010579156363976704
深入拆解PostgreSQL用户权限体系,手把手教你正确授权数据库/Schema,彻底解决使用中常见的权限不足问题(如42501报错)。
PostgreSQL里“用户”和“角色”本质是同一个东西(ROLE),区别仅在于是否有登录权限:
postgres,拥有所有权限,能创建/删除用户、数据库,执行任意操作;admin,无任何默认权限,所有操作都需要授权;PostgreSQL采用「最小粒度、分层独立控制」模型,每一层权限只管自己的范围,类比成“进大楼”更好理解:
权限层级 | 对应对象 | 核心权限 | 类比场景 | 缺失后果 |
|---|---|---|---|---|
数据库级 | Database | 连接(CONNECT)、创建临时表 | 大楼门禁卡 | 连不上数据库 |
模式级 | Schema | 使用(USAGE)、创建(CREATE) | 楼层电梯权限 | 能连库,但看不到表 |
表级 | Table | 查询(SELECT)、删数据(DELETE)、删表(DROP) | 房间钥匙+操作权 | 能看到表,却查不了数据/删不了表 |
序列级 | Sequence | 读取/修改序列值 | 房间内工具使用权 | 自增字段插入数据报错 |
DELETE:删表数据(行级操作),属于数据权限;DROP:删表本身(结构操作),属于管理权限;USAGE:模式/序列的基础访问权(没有它,连表都看不到);ALL PRIVILEGES:看似包含所有权限,但部分场景(如DROP)可能不生效。-- 1. 创建带登录权限的普通用户(替换密码)
CREATE ROLE admin WITH LOGIN PASSWORD 'your_secure_password';
-- 2. 创建目标数据库(指定编码避免中文乱码)
CREATE DATABASE datareport
OWNER postgres
ENCODING 'UTF8'
LC_COLLATE 'zh_CN.UTF-8'
LC_CTYPE 'zh_CN.UTF-8';-- 授予数据库连接、创建临时表权限
GRANT ALL PRIVILEGES ON DATABASE datareport TO admin;💡 作用:允许admin连接数据库;局限:无法访问库内的模式和表。
-- 所有模式/表授权必须在这个上下文执行,否则白做
\c datareport-- 授予模式的使用、创建、删除权限
GRANT USAGE, CREATE, DROPON SCHEMA datareport TO admin;💡 作用:能看到模式下的表;局限:仍无法操作表内数据。
-- 显式授予所有操作权限(重点包含DROP)
GRANT SELECT, INSERT, UPDATE, DELETE, DROP, ALTERON ALL TABLES IN SCHEMA datareport TO admin;-- 避免插入自增字段时报错
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA datareport TO admin;-- 未来新建表自动获权,不用重复授权
ALTER DEFAULT PRIVILEGES IN SCHEMA datareport
GRANT SELECT, INSERT, UPDATE, DELETE, DROPON TABLES TO admin;
-- 未来新建序列自动获权
ALTER DEFAULT PRIVILEGES IN SCHEMA datareport
GRANT ALL PRIVILEGES ON SEQUENCES TO admin;如果授权后仍报权限不足,大概率是表的所有者还是postgres:
-- 方式1:修改单张表所有者(替换表名)
ALTERTABLE datareport.目标表名 OWNER TO admin;
-- 方式2:批量修改所有表所有者(推荐)
DO $$
DECLARE
tbl RECORD;
BEGIN
FOR tbl INSELECT table_name FROM information_schema.tables
WHERE table_schema = 'datareport'AND table_type = 'BASE TABLE' LOOP
EXECUTE 'ALTER TABLE datareport.' || quote_ident(tbl.table_name) || ' OWNER TO admin;';
END LOOP;
END $$;-- 1. 切换到admin用户
SET ROLE admin;
-- 2. 验证连接数据库
\c datareport
-- 3. 验证查询数据(替换表名)
SELECT * FROM datareport.目标表名 LIMIT1;
-- 4. 验证删除表(谨慎!先备份)
-- DROP TABLE IF EXISTS datareport.目标表名;
-- 5. 恢复原用户
RESET ROLE;只做前3步 = 有大楼门禁卡+电梯权限,但没有房间钥匙 → 能进大楼、进楼层,却打不开存放数据的“房间(表)”;做完第4步 = 拿到房间钥匙 → 能正常查数据、操作表;加做第5步 = 拿到房间里的工具 → 能正常使用自增字段。
假设datareport模式下有user_info表:
admin能看到表,但执行SELECT * FROM user_info报42501;不依赖ALL PRIVILEGES通配,精准指定需要的权限(如只授SELECT、只授DROP),核心适用场景:
SELECT);DROP等权限通配授权失效问题;\c datareport
-- 仅授Schema使用权限
GRANT USAGE ON SCHEMA datareport TO read_only_user;
-- 仅授查询权限
GRANT SELECTON ALL TABLES IN SCHEMA datareport TO read_only_user;
-- 未来新建表自动只读
ALTER DEFAULT PRIVILEGES IN SCHEMA datareport GRANT SELECTON TABLES TO read_only_user;\c datareport
-- 显式授DROP权限
GRANT DROPON ALL TABLES IN SCHEMA datareport TO admin;
-- 未来新建表自动有DROP权限
ALTER DEFAULT PRIVILEGES IN SCHEMA datareport GRANT DROPON TABLES TO admin;-- 仅授必要权限,不赋多余权限
GRANT USAGE, SELECT, UPDATEON ALL SEQUENCES IN SCHEMA datareport TO admin;授权方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
显式授权 | 精准、权限最小化、易排查 | 操作稍繁琐 | 生产环境、精细化管控 |
通配授权(ALL) | 操作简单、覆盖全 | 权限过大、部分生效不明确 | 测试环境、全权限用户 |
\c 库名)执行;"DataReport"),授权时要保持一致;-- 查DROP权限
SELECT has_table_privilege('admin', 'datareport.目标表名', 'drop') AS has_drop_priv;
-- 查SELECT权限
SELECT has_table_privilege('admin', 'datareport.目标表名', 'select') AS has_select_priv;DROP等结构操作权限,显式授权比通配更稳;-- 1. 创建用户和数据库
CREATE ROLE admin WITH LOGIN PASSWORD 'your_secure_password';
CREATE DATABASE datareport OWNER postgres ENCODING 'UTF8';
-- 2. 分层显式授权
GRANT CONNECT, CREATEON DATABASE datareport TO admin;
\c datareport
GRANT USAGE, CREATEON SCHEMA datareport TO admin;
GRANT SELECT, INSERT, UPDATE, DELETE, DROPON ALL TABLES IN SCHEMA datareport TO admin;
GRANT USAGE, SELECT, UPDATEON ALL SEQUENCES IN SCHEMA datareport TO admin;
-- 3. 设置未来对象默认权限
ALTER DEFAULT PRIVILEGES IN SCHEMA datareport GRANT SELECT, INSERT, UPDATE, DELETE, DROPON TABLES TO admin;
ALTER DEFAULT PRIVILEGES IN SCHEMA datareport GRANT USAGE, SELECT, UPDATEON SEQUENCES TO admin;
-- 4. 批量修改表所有者(可选)
DO $$
DECLARE
tbl RECORD;
BEGIN
FOR tbl INSELECT table_name FROM information_schema.tables
WHERE table_schema = 'datareport'AND table_type = 'BASE TABLE' LOOP
EXECUTE 'ALTER TABLE datareport.' || quote_ident(tbl.table_name) || ' OWNER TO admin;';
END LOOP;
END $$;🌟 小贴士:PostgreSQL权限管理的核心是“最小权限原则”,生产环境尽量只授必要权限,既安全又能减少权限冲突问题~
本文由ByteHouse原创发布,转载请注明出处