Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@
- Privileges
- [Security Compatibility with MySQL](/security-compatibility-with-mysql.md)
- [Privilege Management](/privilege-management.md)
- [Column-Level Privilege Management](/column-privilege-management.md)
- [User Account Management](/user-account-management.md)
- [TiDB Password Management](/password-management.md)
- [Role-Based Access Control](/role-based-access-control.md)
Expand Down
173 changes: 173 additions & 0 deletions column-privilege-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
---
title: Column-Level Privilege Management
summary: TiDB supports a MySQL-compatible column-level privilege management mechanism, enabling you to grant or revoke `SELECT`, `INSERT`, `UPDATE`, and `REFERENCES` privileges on specific columns of a table using `GRANT` or `REVOKE`, thus achieving finer-grained access control.
---

# Column-Level Privilege Management

Starting from v8.5.6, TiDB supports a MySQL-compatible column-level privilege management mechanism. With column-level privileges, you can grant or revoke `SELECT`, `INSERT`, `UPDATE`, and `REFERENCES` privileges on specific columns of a table, achieving finer-grained data access control.

> **Note:**
>
> Although MySQL syntax allows column-level specification like `REFERENCES(col_name)`, `REFERENCES` itself is a database/table-level privilege used for foreign key-related permission checks. Therefore, column-level `REFERENCES` does not actually take effect in MySQL. TiDB's behavior is consistent with MySQL.

## Syntax

Granting and revoking column-level privileges are similar to table-level privileges, with the following differences:

- The column name list is placed after the **privilege type**, not after the **table name**.
- Multiple column names are separated by commas (`,`).

```sql
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';
```

Where:

* `priv_type` supports `SELECT`, `INSERT`, `UPDATE`, and `REFERENCES`.
* The `ON` clause requires specifying the specific table, for example, `test.tbl`.
* A single `GRANT` or `REVOKE` statement can include multiple privilege items, and each privilege item can specify its own list of column names.

For example, the following statement grants `SELECT` privileges on `col1` and `col2` and `UPDATE` privilege on `col3` to the user:

```sql
GRANT SELECT(col1, col2), UPDATE(col3) ON test.tbl TO 'user'@'host';
```

## Grant column-level privileges

The following example grants the `SELECT` privilege on `col1` and `col2` of table `test.tbl` to user `newuser`, and grants the `UPDATE` privilege on `col3` to the same user:

```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'@'%' |
+---------------------------------------------------------------------+
```

In addition to using `SHOW GRANTS`, you can also view column-level privilege information by querying [`INFORMATION_SCHEMA.COLUMN_PRIVILEGES`](/information-schema/information-schema-columns.md).

## Revoke column-level privileges

The following example revokes the `SELECT` privilege on column `col2` from user `newuser`:

```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'@'%' |
+---------------------------------------------------------------+
```

## Column-level privilege access control example

After granting or revoking column-level privileges, TiDB performs privilege checks on columns referenced in SQL statements. For example:

* `SELECT` statements: `SELECT` column privileges affect columns referenced in the `SELECT` list as well as `WHERE`, `ORDER BY`, and other clauses.
* `UPDATE` statements: columns being updated in the `SET` clause require `UPDATE` column privileges. Columns read in expressions or conditions usually also require `SELECT` column privileges.
* `INSERT` statements: columns being written to require `INSERT` column privileges. `INSERT INTO t VALUES (...)` is equivalent to writing to all columns.

In the following example, user `newuser` can only query `col1` and update `col3`:

```sql
-- Execute as newuser
SELECT col1 FROM tbl;
SELECT * FROM tbl; -- Error (missing SELECT column privilege for col2, col3)

UPDATE tbl SET col3 = 1;
UPDATE tbl SET col1 = 2; -- Error (missing UPDATE column privilege for col1)

UPDATE tbl SET col3 = col1;
UPDATE tbl SET col3 = col3 + 1; -- Error (missing SELECT column privilege for col3)
UPDATE tbl SET col3 = col1 WHERE col1 > 0;
```

## Compatibility differences with MySQL

TiDB's column-level privileges are generally compatible with MySQL. However, there are differences in the following scenarios:

| Scenario | TiDB | MySQL |
| :--------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Revoking column-level privileges not granted to a user | `REVOKE` executes successfully. | `REVOKE` throws an error. |
| Execution order of column pruning and `SELECT` privilege check | `SELECT` column privileges are checked first, then column pruning is performed. For example: executing `SELECT a FROM (SELECT a, b FROM t) s` requires `SELECT` column privileges for both `t.a` and `t.b`. | Column pruning is performed first, then `SELECT` column privileges are checked. For example: executing `SELECT a FROM (SELECT a, b FROM t) s` only requires `SELECT` column privilege for `t.a`. |

### Column pruning and privilege checks in view scenarios

When performing `SELECT` privilege checks on views, MySQL and TiDB differ as follows:

- MySQL first prunes columns in the view's internal query and then checks the column privileges of the internal tables, making the checks relatively lenient in some scenarios.
- TiDB does not perform column pruning before privilege checks, so additional column privileges might be required.

```sql
-- Prepare the environment by logging in as 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'@'%';

-- Log in as u
SELECT a FROM v;
-- MySQL: Error, missing access privileges for t.a, t.c, t.d
-- TiDB: Error, missing access privileges for t.a, t.b, t.c, t.d

-- Log in as root
GRANT SELECT(a, c, d) ON t TO 'u'@'%';

-- Log in as u
SELECT a FROM v;
-- MySQL: Success (internal query is pruned to `SELECT a FROM t WHERE c = 0 ORDER BY d`)
-- TiDB: Error, missing access privileges for t.b

SELECT * FROM v;
-- MySQL: Error, missing access privileges for t.b
-- TiDB: Error, missing access privileges for t.b

-- Log in as root
GRANT SELECT(b) ON t TO 'u'@'%';

-- Log in as u
SELECT * FROM v;
-- MySQL: Success
-- TiDB: Success
```

## See also

* [Privilege Management](/privilege-management.md)
* [`GRANT <privileges>`](/sql-statements/sql-statement-grant-privileges.md)
* [`REVOKE <privileges>`](/sql-statements/sql-statement-revoke-privileges.md)
```
1 change: 0 additions & 1 deletion mysql-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ You can try out TiDB features on [TiDB Playground](https://play.tidbcloud.com/?u
+ Optimizer trace
+ XML Functions
+ X-Protocol [#1109](https://github.com/pingcap/tidb/issues/1109)
+ Column-level privileges [#9766](https://github.com/pingcap/tidb/issues/9766)
+ `XA` syntax (TiDB uses a two-phase commit internally, but this is not exposed via an SQL interface)
+ `CREATE TABLE tblName AS SELECT stmt` syntax [#4754](https://github.com/pingcap/tidb/issues/4754)
+ `CHECK TABLE` syntax [#4673](https://github.com/pingcap/tidb/issues/4673)
Expand Down
1 change: 1 addition & 0 deletions privilege-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Use the following statement to grant the `xxx` user all privileges on all databa
```sql
GRANT ALL PRIVILEGES ON *.* TO 'xxx'@'%';
```
Starting from v8.5.6, TiDB supports the MySQL-compatible column-level privilege management mechanism. You can grant or revoke `SELECT`, `INSERT`, `UPDATE`, and `REFERENCES` privileges for specific columns at the table level. For more information, see [Column-Level Privilege Management](/column-privilege-management.md).

By default, [`GRANT`](/sql-statements/sql-statement-grant-privileges.md) statements will return an error if the user specified does not exist. This behavior depends on if the [SQL mode](/system-variables.md#sql_mode) `NO_AUTO_CREATE_USER` is specified:

Expand Down
2 changes: 1 addition & 1 deletion sql-statements/sql-statement-grant-privileges.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ mysql> SHOW GRANTS FOR 'newuser';
## MySQL compatibility

* Similar to MySQL, the `USAGE` privilege denotes the ability to log into a TiDB server.
* Column level privileges are not currently supported.
* Starting from v8.5.6, TiDB supports a MySQL-compatible column-level privilege management mechanism. You can grant or revoke `SELECT`, `INSERT`, `UPDATE`, and `REFERENCES` privileges on specific columns at the table level. For more information, see [Column-Level Privilege Management](/column-privilege-management.md).
* Similar to MySQL, when the `NO_AUTO_CREATE_USER` sql mode is not present, the `GRANT` statement will automatically create a new user with an empty password when a user does not exist. Removing this sql-mode (it is enabled by default) presents a security risk.
* In TiDB, after the `GRANT <privileges>` statement is executed successfully, the execution result takes effect immediately on the current connection. Whereas [in MySQL, for some privileges, the execution results take effect only on subsequent connections](https://dev.mysql.com/doc/refman/8.0/en/privilege-changes.html). See [TiDB #39356](https://github.com/pingcap/tidb/issues/39356) for details.

Expand Down
1 change: 1 addition & 0 deletions sql-statements/sql-statement-revoke-privileges.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ summary: An overview of the usage of REVOKE <privileges> for the TiDB database.
# `REVOKE <privileges>`

This statement removes privileges from an existing user. Executing this statement requires the `GRANT OPTION` privilege and all privileges you revoke.
Starting from v8.5.6, TiDB supports the MySQL-compatible column-level privilege management mechanism. You can specify a list of column names in `REVOKE`, for example `REVOKE SELECT(col2) ON test.tbl FROM 'user'@'host';`. For more information, see [Column-Level Privilege Management](/column-privilege-management.md).

## Synopsis

Expand Down
Loading