All Products
Search
Document Center

PolarDB:Concurrency Control

Last Updated:Mar 28, 2026

Concurrency Control (CCL) lets you cap the number of SQL statements that run simultaneously on a PolarDB for MySQL cluster. When traffic bursts or resource-heavy queries risk saturating CPU or memory, CCL queues or rejects excess statements before they destabilize the cluster.

Rules are defined in SQL and enforced at the engine level. Each rule targets statements by type, table, keyword, or SQL fingerprint, so you can throttle exactly the workloads that matter without affecting others.

Use cases

  • Traffic burst protection: Cap all SELECT statements so that sudden query spikes do not saturate the cluster.

  • Resource-heavy query isolation: Add a rule targeting a specific table or keyword to throttle expensive queries without affecting other workloads.

  • SQL blacklist: Set Concurrency_count to 0 to block a specific query pattern entirely.

  • Hot table protection: Apply tighter limits to latency-sensitive tables.

Prerequisites

Before you begin, make sure your cluster is one of the following versions:

  • PolarDB for MySQL 8.0

  • PolarDB for MySQL 5.7 with a minor engine version of 5.7.1.0.6 or later

  • PolarDB for MySQL 5.6

If your cluster is PolarDB for MySQL 5.7 with a minor engine version of 5.7.1.0.27 or later, CCL is compatible with Thread Pool.

Usage notes

  • Modify CCL rules on the primary node only. The system automatically syncs changes to read nodes.

How CCL works

Matching dimensions

CCL matches each incoming SQL statement against your rules using up to five dimensions:

DimensionDescription
TYPESQL statement type: SELECT, UPDATE, INSERT, DELETE, or DDL
SCHEMADatabase name
TABLETable or view name
KEYWORDOne or more keywords in the SQL statement. Separate multiple keywords with semicolons (;)
DIGESTA hash derived from the normalized SQL statement. See STATEMENT_DIGEST()

Matching logic

When DIGEST is empty, the rule matches based on TYPE, SCHEMA, and TABLE:

  • If TYPE, SCHEMA, and TABLE are all specified, all three must match.

  • If only TYPE is specified (SCHEMA and TABLE are blank), only the TYPE must match.

When DIGEST is set, the rule matches based on SCHEMA and DIGEST:

  • If SCHEMA is also set, both SCHEMA and DIGEST must match.

  • If SCHEMA is blank, only the DIGEST must match.

Keyword matching (applies when KEYWORD is not empty):

  • A single keyword matches if the SQL statement contains it.

  • Multiple keywords match only if the SQL statement contains all of them. Order does not matter.

Matching priority

Each SQL statement matches at most one CCL rule. If a statement qualifies for multiple rules, PolarDB applies the highest-priority rule. Among rules at the same priority level, the rule with the lower ID wins.

PriorityMatch method
1 (highest)DIGEST value
2TYPE, SCHEMA, and TABLE
3 (lowest)TYPE only

Parameters

Set these parameters in the PolarDB console. For details, see Set cluster and node parameters.

ParameterDescriptionExample
loose_ccl_modeBehavior when the concurrency limit is exceeded. WAIT (default): the statement queues until a slot is available. REFUSE: the statement is rejected immediately with an error. Supported on PolarDB for MySQL 8.0 only. Versions 5.6 and 5.7 always queue.loose_ccl_mode = REFUSE
loose_ccl_max_waiting_countMaximum number of statements that can queue for a single CCL rule when loose_ccl_mode is set to WAIT. If the queue is full, the statement is rejected. Range: 0–65536. Default: 0. Supported on PolarDB for MySQL 5.7 and 8.0.loose_ccl_max_waiting_count = 100

CCL rule table

PolarDB stores all CCL rules in the concurrency_control system table (InnoDB, mysql tablespace). The table is created automatically at startup.

CREATE TABLE concurrency_control (
  Id bigint AUTO_INCREMENT NOT NULL,
  Type varchar(64),
  Schema_name varchar(64),
  Table_name varchar(64),
  Concurrency_count bigint NOT NULL,
  Keywords text,
  State enum('N','Y') COLLATE utf8_general_ci DEFAULT 'Y' NOT NULL,
  Ordered enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
  Digest varchar(64),
  Digest_text longtext,
  Extra mediumtext,
  PRIMARY KEY Rule_id(id)
) Engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin
  COMMENT='Concurrency control' TABLESPACE=mysql;
ColumnDescription
IdCCL rule ID. Rules with lower IDs have higher priority when multiple rules share the same priority level.
TypeSQL statement type: SELECT, UPDATE, INSERT, DELETE, or DDL
Schema_nameDatabase name
Table_nameTable name
Concurrency_countMaximum number of concurrent executions allowed. Set to 0 to block the matched queries entirely (SQL blacklist).
KeywordsKeywords to match. Separate multiple keywords with semicolons (;).
StateWhether the rule is active. Y (default): enabled. N: disabled.
OrderedWhether keywords must appear in order. N (default): any order. Y: must appear in the order listed.
Digest64-byte hash derived from Digest_text. See STATEMENT_DIGEST().
Digest_textNormalized SQL statement features.
ExtraAdditional information.

Manage CCL rules

The DBMS_CCL package provides six stored procedures for managing CCL rules.

add_ccl_rule — Add a rule by type, schema, table, and keyword

dbms_ccl.add_ccl_rule('<Type>', '<Schema_name>', '<Table_name>', <Concurrency_count>, '<Keywords>');

Examples

Limit all SELECT statements to 10 concurrent executions:

CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 10, '');

Limit SELECT statements containing the keyword key1 to 20 concurrent executions:

CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 20, 'key1');

Limit SELECT statements that contain all three keywords (key1, key2, key3) to 20 concurrent executions. The order of the keywords in the SQL statement does not matter:

CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 20, 'key1;key2;key3');

Limit SELECT statements on table t in the test database to 10 concurrent executions:

CALL dbms_ccl.add_ccl_rule('SELECT', 'test', 't', 10, '');

add_ccl_digest_rule — Add a rule by SQL statement text

This procedure calculates the digest from the SQL statement you provide and adds a rule matching that digest.

add_ccl_digest_rule is supported on the following versions:
PolarDB for MySQL 8.0.1 with a minor engine version of 8.0.1.1.31 or later
PolarDB for MySQL 8.0.2 with a minor engine version of 8.0.2.2.12 or later
dbms_ccl.add_ccl_digest_rule('<Schema_name>', '<Query>', <Concurrency_count>);

Examples

Limit SELECT * FROM t1 to 10 concurrent executions, across all schemas:

CALL dbms_ccl.add_ccl_digest_rule("", "SELECT * FROM t1", 10);

Limit SELECT * FROM t1 in the test schema to 10 concurrent executions:

CALL dbms_ccl.add_ccl_digest_rule("test", "SELECT * FROM t1", 10);

Limit SELECT * FROM t1 WHERE col1 = 1 to 10 concurrent executions:

CALL dbms_ccl.add_ccl_digest_rule("", "SELECT * FROM t1 WHERE col1 = 1", 10);
When a SQL statement contains constants, the rule matches regardless of the constant value. For example, the rule above also matches SELECT * FROM t1 WHERE col1 = 2.

add_ccl_digest_rule_by_hash — Add a rule by pre-calculated digest hash

Use this procedure when you already have the digest hash and want to skip the normalization step.

add_ccl_digest_rule_by_hash is supported only on PolarDB for MySQL 8.0.1 with a minor engine version of 8.0.1.1.31 or later.
dbms_ccl.add_ccl_digest_rule_by_hash('<Schema_name>', '<Digest>', <Concurrency_count>);

Examples

Limit statements matching digest 533c0a9cf0cf92d2c26e7fe8821735eb4a72c409aaca24f9f281d137427bfa9a to 10 concurrent executions. This digest corresponds to SELECT * FROM t1, which you can verify by running SELECT statement_digest("SELECT * FROM t1"):

CALL dbms_ccl.add_ccl_digest_rule_by_hash('', '533c0a9cf0cf92d2c26e7fe8821735eb4a72c409aaca24f9f281d137427bfa9a', 10);

Limit the same digest to 10 concurrent executions in the test schema:

CALL dbms_ccl.add_ccl_digest_rule_by_hash('test', '533c0a9cf0cf92d2c26e7fe8821735eb4a72c409aaca24f9f281d137427bfa9a', 10);

del_ccl_rule — Delete a rule

dbms_ccl.del_ccl_rule(<Id>);

Example

Delete the CCL rule with ID 15:

CALL dbms_ccl.del_ccl_rule(15);

If the rule does not exist, PolarDB returns a warning. Run SHOW WARNINGS to inspect it:

CALL dbms_ccl.del_ccl_rule(100);
-- Query OK, 0 rows affected, 2 warnings (0.00 sec)

SHOW WARNINGS;
+---------+------+----------------------------------------------------+
| Level   | Code | Message                                            |
+---------+------+----------------------------------------------------+
| Warning | 7517 | Concurrency control rule 100 is not found in table |
| Warning | 7517 | Concurrency control rule 100 is not found in cache |
+---------+------+----------------------------------------------------+
The warning code differs by version: 7517 for PolarDB for MySQL 8.0, 3267 for 5.7, and 3045 for 5.6.

show_ccl_rule — List active rules

Displays all enabled CCL rules currently loaded in memory.

dbms_ccl.show_ccl_rule();

Example

CALL dbms_ccl.show_ccl_rule();
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
| ID   | TYPE   | SCHEMA | TABLE | STATE | ORDER | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITING  | KEYWORDS |
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
|   17 | SELECT | test   | t     | Y     | N     |                30 |       0 |       0 |        0 |          |
|   16 | SELECT |        |       | Y     | N     |                20 |       0 |       0 |        0 | key1     |
|   18 | SELECT |        |       | Y     | N     |                10 |       0 |       0 |        0 |          |
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+

The output includes three runtime counters per rule:

ColumnDescription
MATCHEDTotal number of times this rule has been matched since the rule was loaded
RUNNINGNumber of threads currently executing statements under this rule
WAITINGNumber of threads currently queued, waiting for a slot

flush_ccl_rule — Apply direct table changes

If you modify the concurrency_control table directly (with an UPDATE or INSERT statement) instead of using the stored procedures, run flush_ccl_rule to reload the rules into memory.

dbms_ccl.flush_ccl_rule();

Example

Update the concurrency count for rule 18, then apply the change:

UPDATE mysql.concurrency_control SET CONCURRENCY_COUNT = 15 WHERE Id = 18;
-- Query OK, 1 row affected (0.00 sec)
-- Rows matched: 1  Changed: 1  Warnings: 0

CALL dbms_ccl.flush_ccl_rule();
-- Query OK, 0 rows affected (0.00 sec)

Adjust rule priority

Lower IDs take higher priority. To reprioritize a rule, update its ID directly:

UPDATE mysql.concurrency_control SET ID = <new_id> WHERE ID = <current_id>;

Example

The current rules, sorted by priority:

CALL dbms_ccl.show_ccl_rule();
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
| ID   | TYPE   | SCHEMA | TABLE | STATE | ORDER | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITING  | KEYWORDS |
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
|   17 | SELECT | test   | t     | Y     | N     |                30 |       0 |       0 |        0 |          |
|   16 | SELECT |        |       | Y     | N     |                20 |       0 |       0 |        0 | key1     |
|   18 | SELECT |        |       | Y     | N     |                10 |       0 |       0 |        0 |          |
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+

Lower the priority of rule 17 by changing its ID to 20:

UPDATE mysql.concurrency_control SET ID = 20 WHERE ID = 17;

Verify the updated order:

CALL dbms_ccl.show_ccl_rule();
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
| ID   | TYPE   | SCHEMA | TABLE | STATE | ORDER | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITING  | KEYWORDS |
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
|   16 | SELECT |        |       | Y     | N     |                20 |       0 |       0 |        0 | key1     |
|   18 | SELECT |        |       | Y     | N     |                10 |       0 |       0 |        0 |          |
|   20 | SELECT | test   | t     | Y     | N     |                30 |       0 |       0 |        0 |          |
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+

Verify CCL rules

After adding rules, confirm they are active and matching the expected traffic.

Check that rules are loaded

CALL dbms_ccl.show_ccl_rule();

Active rules appear in the output. A rule that was added but does not appear has not been loaded — run CALL dbms_ccl.flush_ccl_rule() to reload.

Confirm rules are matching traffic

Run show_ccl_rule() before and after a workload. The MATCHED counter increments each time a rule matches an incoming statement. If MATCHED stays at 0, the rule's dimensions (TYPE, SCHEMA, TABLE, KEYWORD, or DIGEST) may not match your workload.

The RUNNING and WAITING counters show real-time concurrency. For example, RUNNING = 3 and WAITING = 9 means three threads are executing and nine are queued, which confirms the concurrency limit is being enforced.

Functional test example

The following example sets up three rules at different dimensions and runs a Sysbench workload to validate them.

Step 1. Create the rules:

CALL dbms_ccl.add_ccl_rule('SELECT', 'test', 'sbtest1', 3, '');  -- SELECT on test.sbtest1, limit 3
CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 2, 'sbtest2');       -- SELECT with keyword sbtest2, limit 2
CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 2, '');              -- All SELECT statements, limit 2

Step 2. Run a Sysbench workload: 64 threads, 4 tables, select.lua.

Step 3. Check the concurrency counters:

CALL dbms_ccl.show_ccl_rule();
+------+--------+--------+---------+-------+-------+-------------------+---------+---------+----------+----------+
| ID   | TYPE   | SCHEMA | TABLE   | STATE | ORDER | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITING  | KEYWORDS |
+------+--------+--------+---------+-------+-------+-------------------+---------+---------+----------+----------+
|   20 | SELECT | test   | sbtest1 | Y     | N     |                 3 |     389 |       3 |        9 |          |
|   21 | SELECT |        |         | Y     | N     |                 2 |     375 |       2 |       14 | sbtest2  |
|   22 | SELECT |        |         | Y     | N     |                 2 |     519 |       2 |       34 |          |
+------+--------+--------+---------+-------+-------+-------------------+---------+---------+----------+----------+
3 rows in set (0.00 sec)

The RUNNING values (3, 2, 2) match the configured limits, confirming the rules are enforced correctly.