From 8b96e62a006a50732c592a73fc9db50ebea43a36 Mon Sep 17 00:00:00 2001 From: fzzf678 Date: Fri, 13 Mar 2026 15:40:18 +0800 Subject: [PATCH 01/12] docs: document column-level privileges --- TOC.md | 1 + column-privilege-management.md | 160 ++++++++++++++++++ mysql-compatibility.md | 1 - privilege-management.md | 4 +- .../sql-statement-grant-privileges.md | 27 ++- .../sql-statement-revoke-privileges.md | 2 + 6 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 column-privilege-management.md diff --git a/TOC.md b/TOC.md index a76d8dd8c0a2..8a2cfe3e6da6 100644 --- a/TOC.md +++ b/TOC.md @@ -633,6 +633,7 @@ - 权限 - [与 MySQL 安全特性差异](/security-compatibility-with-mysql.md) - [权限管理](/privilege-management.md) + - [列级权限管理](/column-privilege-management.md) - [TiDB 用户账户管理](/user-account-management.md) - [TiDB 密码管理](/password-management.md) - [基于角色的访问控制](/role-based-access-control.md) diff --git a/column-privilege-management.md b/column-privilege-management.md new file mode 100644 index 000000000000..674bae6964ef --- /dev/null +++ b/column-privilege-management.md @@ -0,0 +1,160 @@ +--- +title: 列级权限管理 +summary: TiDB 支持兼容 MySQL 的列级权限管理机制,可通过 GRANT/REVOKE 在表级别对指定列授予或回收 SELECT、INSERT、UPDATE、REFERENCES 权限,实现更细粒度的访问控制。 +--- + +# 列级权限管理 + +从 v8.5.2 开始,TiDB 支持兼容 MySQL 的列级权限管理机制。通过列级权限,你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,从而实现更细粒度的数据访问控制。 + +> **注意:** +> +> 虽然 MySQL 语法允许 `REFERENCES(col_name)` 这种列级写法,但 `REFERENCES` 本身属于数据库/表级权限(用于外键相关的权限检查)。因此,列级 `REFERENCES` 在 MySQL 中并不会真正生效,TiDB 与 MySQL 保持一致。 + +## 语法 + +列级权限的授予和回收与表级权限类似。不同之处在于:在表名后需要指定列名列表,多个列名之间用逗号(`,`)分隔。 + +{{< copyable "sql" >}} + +```sql +GRANT SELECT(col1, col2), UPDATE(col3) ON db_name.tbl_name TO 'user'@'host'; +REVOKE SELECT(col2) ON db_name.tbl_name FROM 'user'@'host'; +``` + +## 授予列级权限 + +以下示例将表 `test.tbl` 的 `col1` 和 `col2` 的 `SELECT` 权限授予用户 `newuser`,并将 `col3` 的 `UPDATE` 权限授予该用户: + +{{< copyable "sql" >}} + +```sql +CREATE DATABASE IF NOT EXISTS test; +USE test; + +DROP TABLE IF EXISTS tbl; +CREATE TABLE tbl (col1 INT, col2 INT, col3 INT); + +DROP USER IF EXISTS 'newuser'@'%'; +CREATE USER 'newuser'@'%'; + +GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'newuser'@'%'; +SHOW GRANTS FOR 'newuser'@'%'; +``` + +``` ++---------------------------------------------------------------------+ +| Grants for newuser@% | ++---------------------------------------------------------------------+ +| GRANT USAGE ON *.* TO 'newuser'@'%' | +| GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'newuser'@'%' | ++---------------------------------------------------------------------+ +``` + +除了使用 `SHOW GRANTS`,你还可以通过查询 `INFORMATION_SCHEMA.COLUMN_PRIVILEGES` 查看列级权限信息。 + +## 回收列级权限 + +以下示例从用户 `newuser` 收回列 `col2` 的 `SELECT` 权限: + +{{< copyable "sql" >}} + +```sql +REVOKE SELECT(col2) ON test.tbl FROM 'newuser'@'%'; +SHOW GRANTS FOR 'newuser'@'%'; +``` + +``` ++---------------------------------------------------------------+ +| Grants for newuser@% | ++---------------------------------------------------------------+ +| GRANT USAGE ON *.* TO 'newuser'@'%' | +| GRANT SELECT(col1), UPDATE(col3) ON test.tbl TO 'newuser'@'%' | ++---------------------------------------------------------------+ +``` + +## 列级权限访问控制示例 + +在授予或回收列级权限后,TiDB 会对 SQL 中引用的列进行权限检查。例如: + +* `SELECT` 语句:`SELECT` 列权限会影响 `SELECT` 列表以及 `WHERE`、`ORDER BY` 等子句中引用的列。 +* `UPDATE` 语句:`SET` 中被更新的列需要 `UPDATE` 列权限;在表达式、条件中被读取的列通常还需要 `SELECT` 列权限。 +* `INSERT` 语句:被写入的列需要 `INSERT` 列权限(`INSERT INTO t VALUES (...)` 等价于写入所有列)。 + +以下示例中,用户 `newuser` 仅能查询 `col1`,并更新 `col3`: + +{{< copyable "sql" >}} + +```sql +-- 以 newuser 登录执行 +SELECT col1 FROM tbl; +SELECT * FROM tbl; -- 报错(缺少 col2、col3 的 SELECT 列权限) + +UPDATE tbl SET col3 = 1; +UPDATE tbl SET col1 = 2; -- 报错(缺少 col1 的 UPDATE 列权限) + +UPDATE tbl SET col3 = col1; +UPDATE tbl SET col3 = col3 + 1; -- 报错(缺少 col3 的 SELECT 列权限) +UPDATE tbl SET col3 = col1 WHERE col1 > 0; +``` + +## 与 MySQL 的兼容性差异 + +TiDB 的列级权限整体与 MySQL 兼容,但在以下场景存在差异(主要表现为 TiDB 检查更严格): + +| 场景 | TiDB | MySQL | +| :-- | :-- | :-- | +| 收回用户未被授予的列级权限 | `REVOKE` 可以成功执行 | `REVOKE` 会报错 | +| 列裁剪与 `SELECT` 列权限检查的执行顺序 | 先检查 `SELECT` 列权限,再进行列裁剪。例如:执行 `SELECT a FROM (SELECT a, b FROM t) s` 需要同时拥有 `t.a` 和 `t.b` 的 `SELECT` 列权限。 | 先进行列裁剪,再检查 `SELECT` 列权限。例如:执行 `SELECT a FROM (SELECT a, b FROM t) s` 只需要 `t.a` 的 `SELECT` 列权限。 | + +## 附录:视图场景的列裁剪与权限检查 + +在对视图进行 `SELECT` 权限检查时,MySQL 会先对视图内部查询做列裁剪,再检查内部表的列权限,因此在某些场景下检查相对宽松。TiDB 不会在权限检查之前做列裁剪,因此可能需要额外的列权限。 + +{{< copyable "sql" >}} + +```sql +-- 以 root 登录准备环境 +DROP USER IF EXISTS 'u'@'%'; +CREATE USER 'u'@'%'; + +DROP TABLE IF EXISTS t; +CREATE TABLE t (a INT, b INT, c INT, d INT); + +DROP VIEW IF EXISTS v; +CREATE SQL SECURITY INVOKER VIEW v AS SELECT a, b FROM t WHERE c = 0 ORDER BY d; + +GRANT SELECT ON v TO 'u'@'%'; + +-- 以 u 登录 +SELECT a FROM v; +-- MySQL:报错,缺少对 t.a、t.c、t.d 的访问权限 +-- TiDB:报错,缺少对 t.a、t.b、t.c、t.d 的访问权限 + +-- 以 root 登录 +GRANT SELECT(a, c, d) ON t TO 'u'@'%'; + +-- 以 u 登录 +SELECT a FROM v; +-- MySQL:成功(会将内部查询裁剪为 `SELECT a FROM t WHERE c = 0 ORDER BY d`) +-- TiDB:报错,缺少对 t.b 的访问权限 + +SELECT * FROM v; +-- MySQL:报错,缺少对 t.b 的访问权限 +-- TiDB:报错,缺少对 t.b 的访问权限 + +-- 以 root 登录 +GRANT SELECT(b) ON t TO 'u'@'%'; + +-- 以 u 登录 +SELECT * FROM v; +-- MySQL:成功 +-- TiDB:成功 +``` + +## 另请参阅 + +* [权限管理](/privilege-management.md) +* [`GRANT `](/sql-statements/sql-statement-grant-privileges.md) +* [`REVOKE `](/sql-statements/sql-statement-revoke-privileges.md) + diff --git a/mysql-compatibility.md b/mysql-compatibility.md index 017df64218c3..8566690bd570 100644 --- a/mysql-compatibility.md +++ b/mysql-compatibility.md @@ -34,7 +34,6 @@ TiDB 高度兼容 MySQL 协议,以及 MySQL 5.7 和 MySQL 8.0 常用的功能 * MySQL 追踪优化器 * XML 函数 * X-Protocol [#1109](https://github.com/pingcap/tidb/issues/1109) -* 列级权限 [#9766](https://github.com/pingcap/tidb/issues/9766) * `XA` 语法(TiDB 内部使用两阶段提交,但并没有通过 SQL 接口公开) * `CREATE TABLE tblName AS SELECT stmt` 语法 [#4754](https://github.com/pingcap/tidb/issues/4754) * `CHECK TABLE` 语法 [#4673](https://github.com/pingcap/tidb/issues/4673) diff --git a/privilege-management.md b/privilege-management.md index 5f77eea4dbb6..d84e6734ee3b 100644 --- a/privilege-management.md +++ b/privilege-management.md @@ -30,6 +30,8 @@ GRANT SELECT ON test.* TO 'xxx'@'%'; GRANT ALL PRIVILEGES ON *.* TO 'xxx'@'%'; ``` +从 v8.5.2 开始,TiDB 支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限。更多信息参见[列级权限管理](/column-privilege-management.md)。 + 默认情况下,如果指定的用户不存在,[`GRANT`](/sql-statements/sql-statement-grant-privileges.md) 语句将报错。该行为受 [SQL 模式](/system-variables.md#sql_mode)中的 `NO_AUTO_CREATE_USER` 控制。 ```sql @@ -573,4 +575,4 @@ User+Host 可能会匹配 `user` 表里面多行,为了处理这种情况,`u TiDB 启动时,会将一些权限检查的表加载到内存,之后使用缓存的数据来验证权限。执行权限管理语句(如 `GRANT`、`REVOKE`、`CREATE USER` 和 `DROP USER`)将立即生效。 -使用 `INSERT`、`DELETE`、`UPDATE` 等语句手动修改 `mysql.user` 等授权表不会立即生效。该行为与 MySQL 兼容。如需立即生效,可以手动执行 [`FLUSH PRIVILEGES`](/sql-statements/sql-statement-flush-privileges.md) 语句更新权限的缓存。 \ No newline at end of file +使用 `INSERT`、`DELETE`、`UPDATE` 等语句手动修改 `mysql.user` 等授权表不会立即生效。该行为与 MySQL 兼容。如需立即生效,可以手动执行 [`FLUSH PRIVILEGES`](/sql-statements/sql-statement-flush-privileges.md) 语句更新权限的缓存。 diff --git a/sql-statements/sql-statement-grant-privileges.md b/sql-statements/sql-statement-grant-privileges.md index 8d8d160e0b15..4575460faa6b 100644 --- a/sql-statements/sql-statement-grant-privileges.md +++ b/sql-statements/sql-statement-grant-privileges.md @@ -98,10 +98,35 @@ SHOW GRANTS FOR 'newuser'; 2 rows in set (0.00 sec) ``` +你还可以在表级别为指定列授予权限,例如: + +{{< copyable "sql" >}} + +```sql +CREATE DATABASE IF NOT EXISTS test; +DROP TABLE IF EXISTS test.tbl; +CREATE TABLE test.tbl (col1 INT, col2 INT, col3 INT); + +DROP USER IF EXISTS 'coluser'@'%'; +CREATE USER 'coluser'@'%'; +GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'coluser'@'%'; +SHOW GRANTS FOR 'coluser'@'%'; +``` + +``` ++---------------------------------------------------------------------+ +| Grants for coluser@% | ++---------------------------------------------------------------------+ +| GRANT USAGE ON *.* TO 'coluser'@'%' | +| GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'coluser'@'%' | ++---------------------------------------------------------------------+ +2 rows in set (0.00 sec) +``` + ## MySQL 兼容性 * 与 MySQL 类似,`USAGE` 权限表示登录 TiDB 服务器的能力。 -* 目前不支持列级权限。 +* TiDB 支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,详见[列级权限管理](/column-privilege-management.md)。 * 与 MySQL 类似,不存在 `NO_AUTO_CREATE_USER` sql 模式时,`GRANT` 语句将在用户不存在时自动创建一个空密码的新用户。删除此 sql-mode(默认情况下已启用)会带来安全风险。 * `GRANT ` 语句执行成功后,在 TiDB 中语句执行的结果会在当前连接立即生效,而 [MySQL 中部分权限的结果需要等到之后的连接才生效](https://dev.mysql.com/doc/refman/8.0/en/privilege-changes.html)。见 [TiDB #39356](https://github.com/pingcap/tidb/issues/39356)。 diff --git a/sql-statements/sql-statement-revoke-privileges.md b/sql-statements/sql-statement-revoke-privileges.md index 8f32a86ccd88..127744e1ed06 100644 --- a/sql-statements/sql-statement-revoke-privileges.md +++ b/sql-statements/sql-statement-revoke-privileges.md @@ -7,6 +7,8 @@ summary: TiDB 数据库中 REVOKE 的使用概况。 `REVOKE ` 语句用于删除已有用户的权限。执行 `REVOKE ` 语句需要拥有分配的权限,并且拥有 `GRANT OPTION` 权限。 +从 v8.5.2 开始,TiDB 支持兼容 MySQL 的列级权限管理机制,你可以在 `REVOKE` 中指定列名列表,例如 `REVOKE SELECT(col2) ON test.tbl FROM 'user'@'host';`。更多信息参见[列级权限管理](/column-privilege-management.md)。 + ## 语法图 ```ebnf+diagram From 9d332130fa574e4af2e7cf7f09aec6bb96c98944 Mon Sep 17 00:00:00 2001 From: fzzf678 Date: Mon, 16 Mar 2026 11:14:51 +0800 Subject: [PATCH 02/12] docs: correct column privilege version scope --- column-privilege-management.md | 3 +-- privilege-management.md | 4 ++-- sql-statements/sql-statement-grant-privileges.md | 2 +- sql-statements/sql-statement-revoke-privileges.md | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/column-privilege-management.md b/column-privilege-management.md index 674bae6964ef..666ed708ccc2 100644 --- a/column-privilege-management.md +++ b/column-privilege-management.md @@ -5,7 +5,7 @@ summary: TiDB 支持兼容 MySQL 的列级权限管理机制,可通过 GRANT/R # 列级权限管理 -从 v8.5.2 开始,TiDB 支持兼容 MySQL 的列级权限管理机制。通过列级权限,你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,从而实现更细粒度的数据访问控制。 +在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制。通过列级权限,你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,从而实现更细粒度的数据访问控制。 > **注意:** > @@ -157,4 +157,3 @@ SELECT * FROM v; * [权限管理](/privilege-management.md) * [`GRANT `](/sql-statements/sql-statement-grant-privileges.md) * [`REVOKE `](/sql-statements/sql-statement-revoke-privileges.md) - diff --git a/privilege-management.md b/privilege-management.md index d84e6734ee3b..4988eae1a2ff 100644 --- a/privilege-management.md +++ b/privilege-management.md @@ -30,7 +30,7 @@ GRANT SELECT ON test.* TO 'xxx'@'%'; GRANT ALL PRIVILEGES ON *.* TO 'xxx'@'%'; ``` -从 v8.5.2 开始,TiDB 支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限。更多信息参见[列级权限管理](/column-privilege-management.md)。 +在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限。更多信息参见[列级权限管理](/column-privilege-management.md)。 默认情况下,如果指定的用户不存在,[`GRANT`](/sql-statements/sql-statement-grant-privileges.md) 语句将报错。该行为受 [SQL 模式](/system-variables.md#sql_mode)中的 `NO_AUTO_CREATE_USER` 控制。 @@ -575,4 +575,4 @@ User+Host 可能会匹配 `user` 表里面多行,为了处理这种情况,`u TiDB 启动时,会将一些权限检查的表加载到内存,之后使用缓存的数据来验证权限。执行权限管理语句(如 `GRANT`、`REVOKE`、`CREATE USER` 和 `DROP USER`)将立即生效。 -使用 `INSERT`、`DELETE`、`UPDATE` 等语句手动修改 `mysql.user` 等授权表不会立即生效。该行为与 MySQL 兼容。如需立即生效,可以手动执行 [`FLUSH PRIVILEGES`](/sql-statements/sql-statement-flush-privileges.md) 语句更新权限的缓存。 +使用 `INSERT`、`DELETE`、`UPDATE` 等语句手动修改 `mysql.user` 等授权表不会立即生效。该行为与 MySQL 兼容。如需立即生效,可以手动执行 [`FLUSH PRIVILEGES`](/sql-statements/sql-statement-flush-privileges.md) 语句更新权限的缓存。 \ No newline at end of file diff --git a/sql-statements/sql-statement-grant-privileges.md b/sql-statements/sql-statement-grant-privileges.md index 4575460faa6b..7a687afb3e9e 100644 --- a/sql-statements/sql-statement-grant-privileges.md +++ b/sql-statements/sql-statement-grant-privileges.md @@ -126,7 +126,7 @@ SHOW GRANTS FOR 'coluser'@'%'; ## MySQL 兼容性 * 与 MySQL 类似,`USAGE` 权限表示登录 TiDB 服务器的能力。 -* TiDB 支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,详见[列级权限管理](/column-privilege-management.md)。 +* 在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,详见[列级权限管理](/column-privilege-management.md)。 * 与 MySQL 类似,不存在 `NO_AUTO_CREATE_USER` sql 模式时,`GRANT` 语句将在用户不存在时自动创建一个空密码的新用户。删除此 sql-mode(默认情况下已启用)会带来安全风险。 * `GRANT ` 语句执行成功后,在 TiDB 中语句执行的结果会在当前连接立即生效,而 [MySQL 中部分权限的结果需要等到之后的连接才生效](https://dev.mysql.com/doc/refman/8.0/en/privilege-changes.html)。见 [TiDB #39356](https://github.com/pingcap/tidb/issues/39356)。 diff --git a/sql-statements/sql-statement-revoke-privileges.md b/sql-statements/sql-statement-revoke-privileges.md index 127744e1ed06..5e815b9e26a1 100644 --- a/sql-statements/sql-statement-revoke-privileges.md +++ b/sql-statements/sql-statement-revoke-privileges.md @@ -7,7 +7,7 @@ summary: TiDB 数据库中 REVOKE 的使用概况。 `REVOKE ` 语句用于删除已有用户的权限。执行 `REVOKE ` 语句需要拥有分配的权限,并且拥有 `GRANT OPTION` 权限。 -从 v8.5.2 开始,TiDB 支持兼容 MySQL 的列级权限管理机制,你可以在 `REVOKE` 中指定列名列表,例如 `REVOKE SELECT(col2) ON test.tbl FROM 'user'@'host';`。更多信息参见[列级权限管理](/column-privilege-management.md)。 +在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制,你可以在 `REVOKE` 中指定列名列表,例如 `REVOKE SELECT(col2) ON test.tbl FROM 'user'@'host';`。更多信息参见[列级权限管理](/column-privilege-management.md)。 ## 语法图 From 49246557b8373355172562671f3d3325e4015760 Mon Sep 17 00:00:00 2001 From: fzzf678 Date: Mon, 16 Mar 2026 13:52:54 +0800 Subject: [PATCH 03/12] docs: remove redundant grant example --- .../sql-statement-grant-privileges.md | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/sql-statements/sql-statement-grant-privileges.md b/sql-statements/sql-statement-grant-privileges.md index 7a687afb3e9e..5b187125493a 100644 --- a/sql-statements/sql-statement-grant-privileges.md +++ b/sql-statements/sql-statement-grant-privileges.md @@ -98,31 +98,6 @@ SHOW GRANTS FOR 'newuser'; 2 rows in set (0.00 sec) ``` -你还可以在表级别为指定列授予权限,例如: - -{{< copyable "sql" >}} - -```sql -CREATE DATABASE IF NOT EXISTS test; -DROP TABLE IF EXISTS test.tbl; -CREATE TABLE test.tbl (col1 INT, col2 INT, col3 INT); - -DROP USER IF EXISTS 'coluser'@'%'; -CREATE USER 'coluser'@'%'; -GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'coluser'@'%'; -SHOW GRANTS FOR 'coluser'@'%'; -``` - -``` -+---------------------------------------------------------------------+ -| Grants for coluser@% | -+---------------------------------------------------------------------+ -| GRANT USAGE ON *.* TO 'coluser'@'%' | -| GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'coluser'@'%' | -+---------------------------------------------------------------------+ -2 rows in set (0.00 sec) -``` - ## MySQL 兼容性 * 与 MySQL 类似,`USAGE` 权限表示登录 TiDB 服务器的能力。 From f6e5a628d384292ea881fe117c14abd259f37c1d Mon Sep 17 00:00:00 2001 From: fzzf678 Date: Mon, 16 Mar 2026 13:59:21 +0800 Subject: [PATCH 04/12] docs: expand column privilege syntax section --- column-privilege-management.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/column-privilege-management.md b/column-privilege-management.md index 666ed708ccc2..6f6949f72e17 100644 --- a/column-privilege-management.md +++ b/column-privilege-management.md @@ -13,13 +13,32 @@ summary: TiDB 支持兼容 MySQL 的列级权限管理机制,可通过 GRANT/R ## 语法 -列级权限的授予和回收与表级权限类似。不同之处在于:在表名后需要指定列名列表,多个列名之间用逗号(`,`)分隔。 +列级权限的授予和回收与表级权限类似。不同之处在于:列名列表跟在权限类型后面,而不是跟在表名后面;多个列名之间使用逗号(`,`)分隔。 {{< copyable "sql" >}} ```sql -GRANT SELECT(col1, col2), UPDATE(col3) ON db_name.tbl_name TO 'user'@'host'; -REVOKE SELECT(col2) ON db_name.tbl_name FROM 'user'@'host'; +GRANT priv_type(col_name [, col_name] ...) [, priv_type(col_name [, col_name] ...)] ... + ON db_name.tbl_name + TO 'user'@'host'; + +REVOKE priv_type(col_name [, col_name] ...) [, priv_type(col_name [, col_name] ...)] ... + ON db_name.tbl_name + FROM 'user'@'host'; +``` + +其中: + +* `priv_type` 支持 `SELECT`、`INSERT`、`UPDATE` 和 `REFERENCES`。 +* `ON` 后需要指定具体表,例如 `test.tbl`。 +* 同一条 `GRANT` 或 `REVOKE` 语句可以包含多个权限项,每个权限项都可以指定自己的列名列表。 + +例如,以下语句表示将 `col1`、`col2` 的 `SELECT` 权限和 `col3` 的 `UPDATE` 权限授予用户: + +{{< copyable "sql" >}} + +```sql +GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'user'@'host'; ``` ## 授予列级权限 From b0179c015f73d1cab4a107336902b8e9e7c6a7d0 Mon Sep 17 00:00:00 2001 From: fzzf678 <108643977+fzzf678@users.noreply.github.com> Date: Mon, 16 Mar 2026 17:51:48 +0800 Subject: [PATCH 05/12] Update privilege-management.md Co-authored-by: Frank945946 <108602632+Frank945946@users.noreply.github.com> --- privilege-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/privilege-management.md b/privilege-management.md index 4988eae1a2ff..5e2f6c37774c 100644 --- a/privilege-management.md +++ b/privilege-management.md @@ -30,7 +30,7 @@ GRANT SELECT ON test.* TO 'xxx'@'%'; GRANT ALL PRIVILEGES ON *.* TO 'xxx'@'%'; ``` -在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限。更多信息参见[列级权限管理](/column-privilege-management.md)。 +从 v8.5.6 版本开始,TiDB 支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限。更多信息参见[列级权限管理](/column-privilege-management.md)。 默认情况下,如果指定的用户不存在,[`GRANT`](/sql-statements/sql-statement-grant-privileges.md) 语句将报错。该行为受 [SQL 模式](/system-variables.md#sql_mode)中的 `NO_AUTO_CREATE_USER` 控制。 From 7128e4da1095a9ae53df6646fbcd242f6b177247 Mon Sep 17 00:00:00 2001 From: fzzf678 Date: Mon, 16 Mar 2026 18:01:05 +0800 Subject: [PATCH 06/12] docs: soften column privilege difference wording --- column-privilege-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/column-privilege-management.md b/column-privilege-management.md index 6f6949f72e17..705e527120fb 100644 --- a/column-privilege-management.md +++ b/column-privilege-management.md @@ -119,7 +119,7 @@ UPDATE tbl SET col3 = col1 WHERE col1 > 0; ## 与 MySQL 的兼容性差异 -TiDB 的列级权限整体与 MySQL 兼容,但在以下场景存在差异(主要表现为 TiDB 检查更严格): +TiDB 的列级权限整体与 MySQL 兼容,但在以下场景存在差异: | 场景 | TiDB | MySQL | | :-- | :-- | :-- | From 4d78657df57672048c36fa28d78514aefd230a33 Mon Sep 17 00:00:00 2001 From: fzzf678 <108643977+fzzf678@users.noreply.github.com> Date: Mon, 16 Mar 2026 18:03:54 +0800 Subject: [PATCH 07/12] Update column-privilege-management.md Co-authored-by: Frank945946 <108602632+Frank945946@users.noreply.github.com> --- column-privilege-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/column-privilege-management.md b/column-privilege-management.md index 705e527120fb..ca1262c0a9c9 100644 --- a/column-privilege-management.md +++ b/column-privilege-management.md @@ -5,7 +5,7 @@ summary: TiDB 支持兼容 MySQL 的列级权限管理机制,可通过 GRANT/R # 列级权限管理 -在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制。通过列级权限,你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,从而实现更细粒度的数据访问控制。 +从 v8.5.6 版本开始,TiDB 支持兼容 MySQL 的列级权限管理机制。通过列级权限,你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,从而实现更细粒度的数据访问控制。 > **注意:** > From 614d10063df92bb5f3d4e7d232b50cab3874d8ea Mon Sep 17 00:00:00 2001 From: houfaxin Date: Tue, 17 Mar 2026 20:09:24 +0800 Subject: [PATCH 08/12] Update column-privilege-management.md --- column-privilege-management.md | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/column-privilege-management.md b/column-privilege-management.md index ca1262c0a9c9..e3832dfd1f3a 100644 --- a/column-privilege-management.md +++ b/column-privilege-management.md @@ -1,6 +1,6 @@ --- title: 列级权限管理 -summary: TiDB 支持兼容 MySQL 的列级权限管理机制,可通过 GRANT/REVOKE 在表级别对指定列授予或回收 SELECT、INSERT、UPDATE、REFERENCES 权限,实现更细粒度的访问控制。 +summary: TiDB 支持兼容 MySQL 的列级权限管理机制,可通过 `GRANT` 或 `REVOKE` 在表级别对指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,实现更细粒度的访问控制。 --- # 列级权限管理 @@ -9,13 +9,14 @@ summary: TiDB 支持兼容 MySQL 的列级权限管理机制,可通过 GRANT/R > **注意:** > -> 虽然 MySQL 语法允许 `REFERENCES(col_name)` 这种列级写法,但 `REFERENCES` 本身属于数据库/表级权限(用于外键相关的权限检查)。因此,列级 `REFERENCES` 在 MySQL 中并不会真正生效,TiDB 与 MySQL 保持一致。 +> 虽然 MySQL 语法允许 `REFERENCES(col_name)` 这种列级写法,但 `REFERENCES` 本身属于数据库/表级权限,用于外键相关的权限检查。因此,列级 `REFERENCES` 在 MySQL 中并不会真正生效。TiDB 的行为与 MySQL 保持一致。 ## 语法 -列级权限的授予和回收与表级权限类似。不同之处在于:列名列表跟在权限类型后面,而不是跟在表名后面;多个列名之间使用逗号(`,`)分隔。 +列级权限的授予和回收与表级权限类似,区别如下: -{{< copyable "sql" >}} +- 列名列表位于**权限类型**后面,而不是位于**表名**后面。 +- 多个列名之间使用逗号(`,`)分隔。 ```sql GRANT priv_type(col_name [, col_name] ...) [, priv_type(col_name [, col_name] ...)] ... @@ -35,8 +36,6 @@ REVOKE priv_type(col_name [, col_name] ...) [, priv_type(col_name [, col_name] . 例如,以下语句表示将 `col1`、`col2` 的 `SELECT` 权限和 `col3` 的 `UPDATE` 权限授予用户: -{{< copyable "sql" >}} - ```sql GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'user'@'host'; ``` @@ -45,8 +44,6 @@ GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'user'@'host'; 以下示例将表 `test.tbl` 的 `col1` 和 `col2` 的 `SELECT` 权限授予用户 `newuser`,并将 `col3` 的 `UPDATE` 权限授予该用户: -{{< copyable "sql" >}} - ```sql CREATE DATABASE IF NOT EXISTS test; USE test; @@ -76,8 +73,6 @@ SHOW GRANTS FOR 'newuser'@'%'; 以下示例从用户 `newuser` 收回列 `col2` 的 `SELECT` 权限: -{{< copyable "sql" >}} - ```sql REVOKE SELECT(col2) ON test.tbl FROM 'newuser'@'%'; SHOW GRANTS FOR 'newuser'@'%'; @@ -97,13 +92,11 @@ SHOW GRANTS FOR 'newuser'@'%'; 在授予或回收列级权限后,TiDB 会对 SQL 中引用的列进行权限检查。例如: * `SELECT` 语句:`SELECT` 列权限会影响 `SELECT` 列表以及 `WHERE`、`ORDER BY` 等子句中引用的列。 -* `UPDATE` 语句:`SET` 中被更新的列需要 `UPDATE` 列权限;在表达式、条件中被读取的列通常还需要 `SELECT` 列权限。 -* `INSERT` 语句:被写入的列需要 `INSERT` 列权限(`INSERT INTO t VALUES (...)` 等价于写入所有列)。 +* `UPDATE` 语句:`SET` 中被更新的列需要 `UPDATE` 列权限。在表达式、条件中被读取的列通常还需要 `SELECT` 列权限。 +* `INSERT` 语句:被写入的列需要 `INSERT` 列权限。`INSERT INTO t VALUES (...)` 等价于写入所有列。 以下示例中,用户 `newuser` 仅能查询 `col1`,并更新 `col3`: -{{< copyable "sql" >}} - ```sql -- 以 newuser 登录执行 SELECT col1 FROM tbl; @@ -120,18 +113,15 @@ UPDATE tbl SET col3 = col1 WHERE col1 > 0; ## 与 MySQL 的兼容性差异 TiDB 的列级权限整体与 MySQL 兼容,但在以下场景存在差异: - -| 场景 | TiDB | MySQL | -| :-- | :-- | :-- | -| 收回用户未被授予的列级权限 | `REVOKE` 可以成功执行 | `REVOKE` 会报错 | +| 场景 | TiDB | MySQL | +| :----------------------- | :-------------------------- | :---------------------------- | +| 收回用户未被授予的列级权限 | `REVOKE` 可以成功执行 | `REVOKE` 会报错 | | 列裁剪与 `SELECT` 列权限检查的执行顺序 | 先检查 `SELECT` 列权限,再进行列裁剪。例如:执行 `SELECT a FROM (SELECT a, b FROM t) s` 需要同时拥有 `t.a` 和 `t.b` 的 `SELECT` 列权限。 | 先进行列裁剪,再检查 `SELECT` 列权限。例如:执行 `SELECT a FROM (SELECT a, b FROM t) s` 只需要 `t.a` 的 `SELECT` 列权限。 | -## 附录:视图场景的列裁剪与权限检查 +### 视图场景的列裁剪与权限检查 在对视图进行 `SELECT` 权限检查时,MySQL 会先对视图内部查询做列裁剪,再检查内部表的列权限,因此在某些场景下检查相对宽松。TiDB 不会在权限检查之前做列裁剪,因此可能需要额外的列权限。 -{{< copyable "sql" >}} - ```sql -- 以 root 登录准备环境 DROP USER IF EXISTS 'u'@'%'; From 7436089ed6234060bdf1eaa7e49691e774012f4f Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Tue, 17 Mar 2026 20:12:07 +0800 Subject: [PATCH 09/12] Apply suggestions from code review --- sql-statements/sql-statement-grant-privileges.md | 2 +- sql-statements/sql-statement-revoke-privileges.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql-statements/sql-statement-grant-privileges.md b/sql-statements/sql-statement-grant-privileges.md index 5b187125493a..3674be7cda7b 100644 --- a/sql-statements/sql-statement-grant-privileges.md +++ b/sql-statements/sql-statement-grant-privileges.md @@ -101,7 +101,7 @@ SHOW GRANTS FOR 'newuser'; ## MySQL 兼容性 * 与 MySQL 类似,`USAGE` 权限表示登录 TiDB 服务器的能力。 -* 在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限,详见[列级权限管理](/column-privilege-management.md)。 +* 从 v8.5.6 版本开始,TiDB 支持兼容 MySQL 的列级权限管理机制。你可以在表级别为指定列授予或回收 `SELECT`、`INSERT`、`UPDATE`、`REFERENCES` 权限。更多信息参见[列级权限管理](/column-privilege-management.md)。 * 与 MySQL 类似,不存在 `NO_AUTO_CREATE_USER` sql 模式时,`GRANT` 语句将在用户不存在时自动创建一个空密码的新用户。删除此 sql-mode(默认情况下已启用)会带来安全风险。 * `GRANT ` 语句执行成功后,在 TiDB 中语句执行的结果会在当前连接立即生效,而 [MySQL 中部分权限的结果需要等到之后的连接才生效](https://dev.mysql.com/doc/refman/8.0/en/privilege-changes.html)。见 [TiDB #39356](https://github.com/pingcap/tidb/issues/39356)。 diff --git a/sql-statements/sql-statement-revoke-privileges.md b/sql-statements/sql-statement-revoke-privileges.md index 5e815b9e26a1..e3fb22cc0e58 100644 --- a/sql-statements/sql-statement-revoke-privileges.md +++ b/sql-statements/sql-statement-revoke-privileges.md @@ -7,7 +7,7 @@ summary: TiDB 数据库中 REVOKE 的使用概况。 `REVOKE ` 语句用于删除已有用户的权限。执行 `REVOKE ` 语句需要拥有分配的权限,并且拥有 `GRANT OPTION` 权限。 -在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制,你可以在 `REVOKE` 中指定列名列表,例如 `REVOKE SELECT(col2) ON test.tbl FROM 'user'@'host';`。更多信息参见[列级权限管理](/column-privilege-management.md)。 +在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制,你可以在 `REVOKE` 中指定列名列表,例如 从 v8.5.6 版本开始,TiDB 支持兼容 MySQL 的列级权限管理机制,你可以在 `REVOKE` 中指定列名列表,例如 `REVOKE SELECT(col2) ON test.tbl FROM 'user'@'host';`。更多信息参见[列级权限管理](/column-privilege-management.md)。 ## 语法图 From e8c62b48543a31afc08f4694113c3a8e728ffb4f Mon Sep 17 00:00:00 2001 From: houfaxin Date: Tue, 17 Mar 2026 20:14:51 +0800 Subject: [PATCH 10/12] Update column-privilege-management.md --- column-privilege-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/column-privilege-management.md b/column-privilege-management.md index e3832dfd1f3a..df1f02bbffdf 100644 --- a/column-privilege-management.md +++ b/column-privilege-management.md @@ -67,7 +67,7 @@ SHOW GRANTS FOR 'newuser'@'%'; +---------------------------------------------------------------------+ ``` -除了使用 `SHOW GRANTS`,你还可以通过查询 `INFORMATION_SCHEMA.COLUMN_PRIVILEGES` 查看列级权限信息。 +除了使用 `SHOW GRANTS`,你还可以通过查询 [`INFORMATION_SCHEMA.COLUMN_PRIVILEGES`](/information-schema/information-schema-columns.md) 查看列级权限信息。 ## 回收列级权限 From 3282ab0ac78b001a6c63c24403ce2ea2447f1ea1 Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Wed, 18 Mar 2026 14:25:43 +0800 Subject: [PATCH 11/12] Apply suggestions from code review --- column-privilege-management.md | 6 +++++- sql-statements/sql-statement-revoke-privileges.md | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/column-privilege-management.md b/column-privilege-management.md index df1f02bbffdf..aee2d234e45a 100644 --- a/column-privilege-management.md +++ b/column-privilege-management.md @@ -113,6 +113,7 @@ UPDATE tbl SET col3 = col1 WHERE col1 > 0; ## 与 MySQL 的兼容性差异 TiDB 的列级权限整体与 MySQL 兼容,但在以下场景存在差异: + | 场景 | TiDB | MySQL | | :----------------------- | :-------------------------- | :---------------------------- | | 收回用户未被授予的列级权限 | `REVOKE` 可以成功执行 | `REVOKE` 会报错 | @@ -120,7 +121,10 @@ TiDB 的列级权限整体与 MySQL 兼容,但在以下场景存在差异: ### 视图场景的列裁剪与权限检查 -在对视图进行 `SELECT` 权限检查时,MySQL 会先对视图内部查询做列裁剪,再检查内部表的列权限,因此在某些场景下检查相对宽松。TiDB 不会在权限检查之前做列裁剪,因此可能需要额外的列权限。 +在对视图进行 `SELECT` 权限检查时,MySQL 和 TiDB 存在以下差异: + +- MySQL 会先对视图内部查询做列裁剪,再检查内部表的列权限,因此在某些场景下检查相对宽松。 +- TiDB 不会在权限检查之前做列裁剪,因此可能需要额外的列权限。 ```sql -- 以 root 登录准备环境 diff --git a/sql-statements/sql-statement-revoke-privileges.md b/sql-statements/sql-statement-revoke-privileges.md index e3fb22cc0e58..c16f982b684d 100644 --- a/sql-statements/sql-statement-revoke-privileges.md +++ b/sql-statements/sql-statement-revoke-privileges.md @@ -7,7 +7,7 @@ summary: TiDB 数据库中 REVOKE 的使用概况。 `REVOKE ` 语句用于删除已有用户的权限。执行 `REVOKE ` 语句需要拥有分配的权限,并且拥有 `GRANT OPTION` 权限。 -在 TiDB v8.5.6 及后续 8.5.x 版本中,支持兼容 MySQL 的列级权限管理机制,你可以在 `REVOKE` 中指定列名列表,例如 从 v8.5.6 版本开始,TiDB 支持兼容 MySQL 的列级权限管理机制,你可以在 `REVOKE` 中指定列名列表,例如 `REVOKE SELECT(col2) ON test.tbl FROM 'user'@'host';`。更多信息参见[列级权限管理](/column-privilege-management.md)。 +从 v8.5.6 版本开始,TiDB 支持兼容 MySQL 的列级权限管理机制,你可以在 `REVOKE` 中指定列名列表,例如,`REVOKE SELECT(col2) ON test.tbl FROM 'user'@'host';`。更多信息参见[列级权限管理](/column-privilege-management.md)。 ## 语法图 From 04d4d91bf872110de1e31331b50ebd1b43c3de1c Mon Sep 17 00:00:00 2001 From: fzzf678 Date: Wed, 18 Mar 2026 17:38:00 +0800 Subject: [PATCH 12/12] docs: fix privilege docs inconsistencies --- column-privilege-management.md | 2 +- information-schema/information-schema.md | 6 +++--- privilege-management.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/column-privilege-management.md b/column-privilege-management.md index aee2d234e45a..ae38fa3c3eaa 100644 --- a/column-privilege-management.md +++ b/column-privilege-management.md @@ -67,7 +67,7 @@ SHOW GRANTS FOR 'newuser'@'%'; +---------------------------------------------------------------------+ ``` -除了使用 `SHOW GRANTS`,你还可以通过查询 [`INFORMATION_SCHEMA.COLUMN_PRIVILEGES`](/information-schema/information-schema-columns.md) 查看列级权限信息。 +除了使用 `SHOW GRANTS`,你还可以通过查询 `INFORMATION_SCHEMA.COLUMN_PRIVILEGES` 查看列级权限信息。 ## 回收列级权限 diff --git a/information-schema/information-schema.md b/information-schema/information-schema.md index 772e336423d0..344a212f9aed 100644 --- a/information-schema/information-schema.md +++ b/information-schema/information-schema.md @@ -18,7 +18,7 @@ Information Schema 提供了一种查看系统元数据的 ANSI 标准方法。 | [`COLLATIONS`](/information-schema/information-schema-collations.md) | 提供 TiDB 支持的排序规则列表。 | | [`COLLATION_CHARACTER_SET_APPLICABILITY`](/information-schema/information-schema-collation-character-set-applicability.md) | 说明哪些排序规则适用于哪些字符集。 | | [`COLUMNS`](/information-schema/information-schema-columns.md) | 提供所有表中列的列表。 | -| `COLUMN_PRIVILEGES` | TiDB 未实现,返回零行。 | +| `COLUMN_PRIVILEGES` | 汇总当前用户可见的列权限信息。 | | `COLUMN_STATISTICS` | TiDB 未实现,返回零行。 | | [`ENGINES`](/information-schema/information-schema-engines.md) | 提供支持的存储引擎列表。 | | `EVENTS` | TiDB 未实现,返回零行。 | @@ -36,14 +36,14 @@ Information Schema 提供了一种查看系统元数据的 ANSI 标准方法。 | `REFERENTIAL_CONSTRAINTS` | 提供有关 `FOREIGN KEY` 约束的信息。 | | `ROUTINES` | TiDB 未实现,返回零行。 | | [`SCHEMATA`](/information-schema/information-schema-schemata.md) | 提供与 `SHOW DATABASES` 命令类似的信息。 | -| `SCHEMA_PRIVILEGES` | TiDB 未实现,返回零行。 | +| `SCHEMA_PRIVILEGES` | 汇总当前用户可见的数据库权限信息。 | | `SESSION_STATUS` | TiDB 未实现,返回零行。 | | [`SESSION_VARIABLES`](/information-schema/information-schema-session-variables.md) | 提供与 `SHOW SESSION VARIABLES` 命令类似的功能。 | | [`STATISTICS`](/information-schema/information-schema-statistics.md) | 提供有关表索引的信息。 | | [`TABLES`](/information-schema/information-schema-tables.md) | 提供当前用户可见的表的列表。 类似于 `SHOW TABLES`。 | | `TABLESPACES` | TiDB 未实现,返回零行。 | | [`TABLE_CONSTRAINTS`](/information-schema/information-schema-table-constraints.md) | 提供有关主键、唯一索引和外键的信息。 | -| `TABLE_PRIVILEGES` | TiDB 未实现,返回零行。 | +| `TABLE_PRIVILEGES` | 汇总当前用户可见的表权限信息。 | | `TRIGGERS` | TiDB 未实现,返回零行。 | | [`USER_ATTRIBUTES`](/information-schema/information-schema-user-attributes.md) | 汇总用户的注释和属性信息。 | | [`USER_PRIVILEGES`](/information-schema/information-schema-user-privileges.md) | 汇总与当前用户相关的权限。 | diff --git a/privilege-management.md b/privilege-management.md index 5e2f6c37774c..f4acf613cbc5 100644 --- a/privilege-management.md +++ b/privilege-management.md @@ -516,7 +516,7 @@ SELECT * FROM INFORMATION_SCHEMA.USER_PRIVILEGES WHERE grantee = "'root'@'%'"; - `mysql.user`:用户账户,全局权限 - `mysql.db`:数据库级别的权限 - `mysql.tables_priv`:表级别的权限 -- `mysql.columns_priv`:列级别的权限,当前暂不支持 +- `mysql.columns_priv`:列级别的权限(从 v8.5.6 开始支持) 这几张表包含了数据的生效范围和权限信息。例如,`mysql.user` 表的部分数据: