diff --git a/mysql-schema/mysql-schema-user.md b/mysql-schema/mysql-schema-user.md
index 5c4564b5134a8..69ef40dce8f45 100644
--- a/mysql-schema/mysql-schema-user.md
+++ b/mysql-schema/mysql-schema-user.md
@@ -63,8 +63,9 @@ The output is as follows:
| Password_expired | enum('N','Y') | NO | | N | |
| Password_last_changed | timestamp | YES | | CURRENT_TIMESTAMP | |
| Password_lifetime | smallint unsigned | YES | | NULL | |
+| max_user_connections | int unsigned | NO | | 0 | |
+------------------------+-------------------+------+------+-------------------+-------+
-44 rows in set (0.00 sec)
+45 rows in set (0.00 sec)
```
The `mysql.user` table contains several fields that can be categorized into three groups:
diff --git a/security-compatibility-with-mysql.md b/security-compatibility-with-mysql.md
index d795556f619ab..7daed60607a32 100644
--- a/security-compatibility-with-mysql.md
+++ b/security-compatibility-with-mysql.md
@@ -11,7 +11,7 @@ TiDB supports security features similar to MySQL 5.7, and also supports some sec
## Unsupported security features
- Column level permissions.
-- These permission attributes: `max_questions`, `max_updated`, and `max_user_connections`.
+- These permission attributes: `max_questions` and `max_updated`.
- Password verification policy, which requires you to verify the current password when you change it.
- Dual password policy.
- Random password generation.
diff --git a/sql-statements/sql-statement-alter-user.md b/sql-statements/sql-statement-alter-user.md
index 6e4fb809fc5a1..426d9825c4e88 100644
--- a/sql-statements/sql-statement-alter-user.md
+++ b/sql-statements/sql-statement-alter-user.md
@@ -32,6 +32,9 @@ Username ::=
AuthOption ::=
( 'IDENTIFIED' ( 'BY' ( AuthString | 'PASSWORD' HashString ) | 'WITH' StringName ( 'BY' AuthString | 'AS' HashString )? ) )?
+ConnectionOptions ::=
+ ( 'WITH' 'MAX_USER_CONNECTIONS' N )?
+
PasswordOption ::= ( 'PASSWORD' 'EXPIRE' ( 'DEFAULT' | 'NEVER' | 'INTERVAL' N 'DAY' )? | 'PASSWORD' 'HISTORY' ( 'DEFAULT' | N ) | 'PASSWORD' 'REUSE' 'INTERVAL' ( 'DEFAULT' | N 'DAY' ) | 'FAILED_LOGIN_ATTEMPTS' N | 'PASSWORD_LOCK_TIME' ( N | 'UNBOUNDED' ) )*
LockOption ::= ( 'ACCOUNT' 'LOCK' | 'ACCOUNT' 'UNLOCK' )?
@@ -155,6 +158,22 @@ ALTER USER 'newuser' PASSWORD REUSE INTERVAL 90 DAY;
Query OK, 0 rows affected (0.02 sec)
```
+Use `ALTER USER ... WITH MAX_USER_CONNECTIONS N` to modify the maximum connection limit for `newuser`:
+
+```sql
+ALTER USER 'newuser' WITH MAX_USER_CONNECTIONS 3;
+SELECT User, Host, max_user_connections FROM mysql.user WHERE User='newuser';
+```
+
+```
++---------+------+----------------------+
+| User | Host | max_user_connections |
++---------+------+----------------------+
+| newuser | % | 3 |
++---------+------+----------------------+
+1 row in set (0.01 sec)
+```
+
### Modify the resource group bound to the user
Use `ALTER USER ... RESOURCE GROUP` to modify the resource group of the user `newuser` to `rg1`.
diff --git a/sql-statements/sql-statement-create-user.md b/sql-statements/sql-statement-create-user.md
index 5ee1ba1f2a4ae..9bd54c08d0612 100644
--- a/sql-statements/sql-statement-create-user.md
+++ b/sql-statements/sql-statement-create-user.md
@@ -36,6 +36,9 @@ StringName ::=
stringLit
| Identifier
+ConnectionOptions ::=
+ ( 'WITH' 'MAX_USER_CONNECTIONS' N )?
+
PasswordOption ::= ( 'PASSWORD' 'EXPIRE' ( 'DEFAULT' | 'NEVER' | 'INTERVAL' N 'DAY' )?
| 'PASSWORD' 'HISTORY' ( 'DEFAULT' | N )
| 'PASSWORD' 'REUSE' 'INTERVAL' ( 'DEFAULT' | N 'DAY' )
@@ -142,6 +145,22 @@ Create a user whose password is manually expired:
CREATE USER 'newuser9'@'%' PASSWORD EXPIRE;
```
+Create a user with a maximum connection limit of 3:
+
+```sql
+CREATE USER 'newuser10'@'%' WITH MAX_USER_CONNECTIONS 3;
+SELECT User, Host, max_user_connections FROM mysql.user WHERE User='newuser10';
+```
+
+```
++-----------+------+----------------------+
+| user | host | max_user_connections |
++-----------+------+----------------------+
+| newuser10 | % | 3 |
++-----------+------+----------------------+
+1 row in set (0.01 sec)
+```
+
```
Query OK, 1 row affected (0.02 sec)
```
@@ -149,15 +168,15 @@ Query OK, 1 row affected (0.02 sec)
Create a user that uses the resource group `rg1`.
```sql
-CREATE USER 'newuser7'@'%' RESOURCE GROUP rg1;
-SELECT USER, HOST, USER_ATTRIBUTES FROM MYSQL.USER WHERE USER='newuser7';
+CREATE USER 'newuser11'@'%' RESOURCE GROUP rg1;
+SELECT USER, HOST, USER_ATTRIBUTES FROM MYSQL.USER WHERE USER='newuser11';
```
```sql
+----------+------+---------------------------+
| USER | HOST | USER_ATTRIBUTES |
+----------+------+---------------------------+
-| newuser7 | % | {"resource_group": "rg1"} |
+| newuser11| % | {"resource_group": "rg1"} |
+----------+------+---------------------------+
1 rows in set (0.00 sec)
```
@@ -169,7 +188,6 @@ The following `CREATE USER` options are not yet supported by TiDB, and will be p
* `PASSWORD REQUIRE CURRENT DEFAULT`
* `WITH MAX_QUERIES_PER_HOUR`
* `WITH MAX_UPDATES_PER_HOUR`
-* `WITH MAX_USER_CONNECTIONS`
The following `CREATE USER` options are not supported by TiDB either, and are *not* accepted by the parser:
diff --git a/system-variables.md b/system-variables.md
index 95e13c7c391ce..8eef5f8fe6730 100644
--- a/system-variables.md
+++ b/system-variables.md
@@ -658,6 +658,18 @@ This variable is an alias for [`last_insert_id`](#last_insert_id).
- In the `SESSION` scope, this variable is read-only.
- This variable is compatible with MySQL.
+### max_user_connections New in v9.0.0
+
+- Scope: GLOBAL
+- Persists to cluster: Yes
+- Applies to hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value): No
+- Type: Integer
+- Default value: `0`
+- Range: `[0, 100000]`
+- This variable controls the maximum number of connections a user can establish to a TiDB server instance. It is used for resource control.
+- The default value `0` means there is no limit for user connections. When the value is greater than `0` and the number of user connections reaches this value, the TiDB server will reject the user's new connection.
+- If the value of this variable exceeds [`max_connections`](https://docs.pingcap.com/tidb/stable/tidb-configuration-file#max_connections), TiDB uses `max_connections` to limit the maximum number of connections a single user can establish. For example, if `max_user_connections` of a user is set to `2000`, but `max_connections` is `1000`, the user can actually establish up to `1000` connections to a TiDB server instance.
+
### password_history New in v6.5.0
- Scope: GLOBAL