SQL详解之DCL - 数据控制语言完整指南

引言

数据库里通常会有多个应用、多个用户同时访问,如果某个临时账号就能删库、查密码表,那后果不堪设想。
数据库的三种核心语言里,DDL 负责建结构,DML 负责处理数据,而 DCL(数据控制语言)专门解决“谁能碰什么数据、能碰多少”的问题,堪称数据库的“安全守门员”。

这篇文章会从 DCL 的基础概念讲起,分别用 MySQL 和 PostgreSQL 实操演示怎么管理用户、怎么授权和收权,最后给出一套直接可用的安全规范,帮你从零构建安全的数据库访问体系。


1. DCL基础扫盲

1.1 DCL是什么?

DCL 就像数据库的门禁+房卡系统

  • GRANT → 给别人发房卡(授予对象权限)
  • REVOKE → 收走房卡(撤销已给的权限)
  • DENY → 把人拉黑(部分数据库支持,覆盖所有授权)

只要用好这三板斧,就能精确控制每个数据库操作的安全边界。

1.2 常用权限表

无论 MySQL 还是 PostgreSQL,核心权限的含义都差不多,记住这张表就行:

权限类型适用对象通俗说明
SELECT表 / 视图 / 列看数据的权限
INSERT表 / 列增加新数据的权限
UPDATE表 / 列修改现有数据的权限
DELETE删除数据的权限
CREATE库 / 表 / 视图 / 模式创建对象的权限
DROP库 / 表 / 视图 / 模式删除对象的权限
ALL PRIVILEGES所有对象超级房卡,慎用!

2. 先建好「人」:用户/角色管理

2.1 MySQL 用户管理(5.7+ 通用,8.0+ 增强)

MySQL 在 8.0 之前,“用户”和“角色”是分开的,8.0 之后才统一成类似 PostgreSQL 的模型。
这里先用最通用的方式演示。

核心操作

-- 1. 创建用户(Host 很重要!用来限制连接来源)
CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'P@ssw0rd!202x';    -- 只能本地连
CREATE USER 'analyst'@'192.168.1.%' IDENTIFIED BY 'S3cur3Rep0rt'; -- 仅允许指定 IP 段

-- 2. 查看现有用户
SELECT User, Host FROM mysql.user;

-- 3. 修改密码(8.0 推荐用 ALTER,老版本兼容好)
ALTER USER 'webapp'@'localhost' IDENTIFIED BY 'N3wP@ss!202x';

-- 4. 删除用户
DROP USER 'analyst'@'192.168.1.%';

2.2 PostgreSQL 用户/角色管理(原生统一!)

PostgreSQL 里没有单独的“用户”命令,所有账号都是带有不同属性的“角色”:

  • 能登录的叫 LOGIN 角色(其实就是用户)
  • 不能登录的叫 NOLOGIN 角色(用于分组)

核心操作

-- 1. 创建能登录的用户
CREATE ROLE webapp LOGIN PASSWORD 'P@ssw0rd!202x';
-- 也可以直接使用 CREATE USER(内部等价)
CREATE USER analyst PASSWORD 'S3cur3Rep0rt';

-- 2. 创建不能登录的组(用来批量授权)
CREATE ROLE app_developer NOLOGIN;
CREATE ROLE report_reader NOLOGIN;

-- 3. 查看现有角色(psql 快捷命令 \du,或标准 SQL)
SELECT rolname, rolsuper, rolcreatedb FROM pg_roles;

-- 4. 删除角色(必须先回收其所有权限)
DROP ROLE report_reader;

3. 再管好「权限」:GRANT / REVOKE

3.1 MySQL 权限授予(Host 别漏!)

MySQL 的权限是绑定到 User@Host 上的,漏写 Host 很容易导致授权不生效

常用场景

-- 1. 给应用表级权限(最安全!不要直接给库级 ALL)
GRANT SELECT, INSERT, UPDATE ON company_db.employees TO 'webapp'@'localhost';
GRANT SELECT ON company_db.departments TO 'webapp'@'localhost';

-- 2. 临时管理员权限(用完记得回收)
GRANT ALL PRIVILEGES ON company_db.* TO 'dba_temp'@'localhost';

-- 3. 刷新权限(ALTER 或 GRANT 后通常自动刷新,但 CREATE/DROP 后可能需手动执行)
FLUSH PRIVILEGES;

-- 4. 查看已授予的权限
SHOW GRANTS FOR 'webapp'@'localhost';

3.2 MySQL 权限撤销

-- 1. 收回单个权限
REVOKE UPDATE ON company_db.employees FROM 'webapp'@'localhost';

-- 2. 收回所有权限
REVOKE ALL PRIVILEGES ON company_db.* FROM 'dba_temp'@'localhost';

-- 3. 一定要刷新!
FLUSH PRIVILEGES;

3.3 PostgreSQL 权限授予(别忘了先给 schema 的 USAGE!)

PostgreSQL 有一个极容易踩的坑:必须显式授予 schema 的 USAGE 权限,否则即使拥有表权限,也看不见表。

常用场景

-- 0. 先给 public 模式的使用权限(必做!)
GRANT USAGE ON SCHEMA public TO webapp;

-- 1. 给应用表级权限
GRANT SELECT, INSERT, UPDATE ON TABLE employees TO webapp;
GRANT SELECT ON TABLE departments TO webapp;

-- 2. 批量授权当前已有表
GRANT SELECT ON ALL TABLES IN SCHEMA public TO report_reader;

-- 3. 批量授权将来创建的表(MySQL 8.0 才开始有限支持!)
ALTER DEFAULT PRIVILEGES IN SCHEMA public 
GRANT SELECT, INSERT ON TABLES TO webapp;

-- 4. 查看表权限(psql 快捷命令 \dp,或标准 SQL)
\dp employees

3.4 PostgreSQL 权限撤销

-- 1. 收回单个表权限
REVOKE UPDATE ON TABLE employees FROM webapp;

-- 2. 收回未来表的默认授权
ALTER DEFAULT PRIVILEGES IN SCHEMA public 
REVOKE SELECT, INSERT ON TABLES FROM webapp;

4. 安全最佳实践(必看!别踩坑)

4.1 永远遵循「最小权限原则」

两条红线别碰

  • 不给应用账号库级 ALL PRIVILEGES
  • 不让应用账号成为 SUPERUSER

MySQL 示例:标准电商应用账号

CREATE USER 'ecommerce'@'localhost' IDENTIFIED BY 'Ec0mm3rc3!202x';
GRANT SELECT, INSERT, UPDATE ON ecommerce_db.orders TO 'ecommerce'@'localhost';
GRANT SELECT, INSERT ON ecommerce_db.order_items TO 'ecommerce'@'localhost';
GRANT SELECT ON ecommerce_db.products TO 'ecommerce'@'localhost';
FLUSH PRIVILEGES;

4.2 用「角色(组)」批量授权

不要逐个给员工授权!先建组(NOLOGIN 角色),把权限全部授予组,最后把用户加入组。

PostgreSQL 示例:标准公司权限体系

-- 1. 建组
CREATE ROLE app_developer NOLOGIN;
CREATE ROLE sales_reader NOLOGIN;
CREATE ROLE finance_writer NOLOGIN;

-- 2. 给组批量授权
GRANT USAGE ON SCHEMA public TO app_developer, sales_reader, finance_writer;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO app_developer;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO sales_reader;
GRANT SELECT, UPDATE ON finance_salaries TO finance_writer;

-- 3. 未来表的默认授权(新加入的组员自动继承)
ALTER DEFAULT PRIVILEGES IN SCHEMA public 
GRANT ALL PRIVILEGES ON TABLES TO app_developer;

-- 4. 把人加到组里(三个新用户,对应不同组)
CREATE USER lily LOGIN IN ROLE app_developer PASSWORD 'L1lyDev!202x';
CREATE USER tom LOGIN IN ROLE sales_reader PASSWORD 'T0mS3ll!202x';

4.3 限制登录来源

  • MySQL 严格设置 Host 字段,非必要不给 @'%'
  • PostgreSQL 通过 pg_hba.conf 配置文件控制 IP 范围,同样别全开放

5. MySQL vs PostgreSQL DCL 核心差异(一分钟速查)

特性MySQLPostgreSQL
用户/角色关系8.0 后统一,之前分开原生统一,所有都是角色
必给的基础权限无特殊要求必须显式授予 schema USAGE
批量授权未来对象8.0 开始有限支持ALTER DEFAULT PRIVILEGES 非常完善
权限绑定方式绑定 User@Host绑定角色

相关教程

最后再啰嗦一句:定期(比如每月)用 `SHOW GRANTS`(MySQL)或 `\du` + `\dp`(PostgreSQL)审查一次用户权限,及时收走离职或闲置账号的权限,把安全漏洞堵在门外!

总结

DCL 就是数据库的“安全盾牌”,记住三个要点就够用:

  1. 先建角色(组),批量授权,别挨个给用户发权限
  2. 永远遵循最小权限原则,应用账号只给必要的表级操作
  3. 限制登录来源,并且定期审查权限列表

MySQL 的 DCL 简单直接,适合快速上线;PostgreSQL 的 DCL 更精细强大,适合对安全要求更高的场景。选对工具,用好 DCL,你的数据库就能又稳又安全。