max_connect_errors=1 is accepted but TiDB does not block a host after an aborted handshake
- Dominant language
- Go
- Stars
- 40.5k
- Forks
- 6.2k
- PR merge metrics
- PR metrics pending
Description
## Bug Report
Please answer these questions before submitting your issue. Thanks!
### 1. Minimal reproduce step (Required)
```sql
-- On both engines, create a probe user reachable from a non-loopback client IP.
CREATE USER 'maxconn_probe'@'%' IDENTIFIED BY 'probe';
SET GLOBAL max_connect_errors=1;
SELECT @@global.max_connect_errors;
-- MySQL: also TRUNCATE TABLE performance_schema.host_cache;
```
From the probe IP, open a raw TCP socket, read the initial handshake, and close without sending a response. Then attempt a valid connection:
```bash
mysql -h -P -umaxconn_probe -pprobe -e "SELECT 'PROBE_LOGIN_OK';"
```
Probe output:
```text
MYSQL_INITIAL_HANDSHAKE_BYTES=77
MYSQL_AFTER_ABORT_RC=1
MYSQL_AFTER_ABORT_ERR=ERROR 1129 (HY000): Host '192.168.206.32' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'
MYSQL_MAX_CONNECT_ERRORS_ENFORCED
TIDB_INITIAL_HANDSHAKE_BYTES=112
TIDB_AFTER_ABORT_RC=0
TIDB_AFTER_ABORT_OUT='PROBE_LOGIN_OK'
TIDB_MAX_CONNECT_ERRORS_IGNORED
```
Both engines reported `@@global.max_connect_errors=1` before the abort. MySQL blocked the probe IP after one aborted handshake; TiDB allowed the valid connection from the same IP.
### 2. What did you expect to see? (Required)
After `max_connect_errors` successive handshake failures from one host, the server must block that host with MySQL-compatible `ERROR 1129` until the host cache is flushed. If TiDB does not support host-error blocking, `SET GLOBAL max_connect_errors` must fail explicitly instead of reporting a value that the connection path ignores.
### 3. What did you see instead (Required)
MySQL 8.3: max_connect_errors=1; truncate host cache; one raw aborted handshake from 192.168.206.32; valid probe-user connection -> ERROR 1129. TiDB a514: max_connect_errors=1; one raw aborted handshake from 192.168.206.32; valid probe-user connection -> PROBE_LOGIN_OK.
### 4. What is your TiDB version? (Required)
```text
Release Version: v8.4.0-this-is-a-placeholder
Edition: Community
Git Commit Hash: None
Git Branch: None
UTC Build Time: None
GoVersion: go1.25.12
Race Enabled: false
Check Table Before Drop: false
Store: unistore
Kernel Type: Classic
```
Built from source commit `a514a92784c9654502686e6ee6efc9e0aeda8afa` (pingcap/tidb master, 2026-09-07).
### 5. Root cause (optional)
- pkg/sessionctx/variable/noop.go:74 registers max_connect_errors as a noop variable
- pkg/sessionctx/variable/noop.go:141 registers host_cache_size as a noop variable
- pkg/errno/errname.go:155 defines ErrHostIsBlocked but no pkg/server connection path uses it
- no pkg/server path counts per-host handshake errors or reads max_connect_errors/host_cache_size
Contributor guide
Research direction
Start with the noop registrations in pkg/sessionctx/variable/noop.go and ErrHostIsBlocked in pkg/errno/errname.go, then trace the pkg/server connection and handshake path. Reproduce the aborted-handshake sequence from the issue and inspect how host errors, max_connect_errors, and host_cache_size are currently handled. Done means repeated handshake failures produce MySQL-compatible ERROR 1129, or unsupported settings fail explicitly, with regression coverage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, mysql
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100