`connect_timeout` is accepted but TiDB never closes a stalled unauthenticated client after timeout
- 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)
No SQL table is required. Run on TiDB a514 and MySQL 8.3:
```sql
SET GLOBAL connect_timeout=2;
SELECT @@global.connect_timeout;
```
Then open a raw TCP socket to the server, read the initial handshake packet, send nothing, and wait longer than two seconds.
Probe output:
```text
MYSQL_INITIAL_HANDSHAKE_BYTES=77
MYSQL_AFTER_3.5S=ERROR_PACKET_BYTES=54
MYSQL_CONNECT_TIMEOUT_ENFORCED
TIDB_INITIAL_HANDSHAKE_BYTES=112
TIDB_AFTER_12.5S=STILL_OPEN
TIDB_CONNECT_TIMEOUT_IGNORED result=open
```
MySQL control: after about two seconds the stalled client receives an error packet and the peer closes. TiDB: the stalled client is still open after 12.5 seconds, with no error packet. Both engines report `@@global.connect_timeout=2` before the probe.
### 2. What did you expect to see? (Required)
An unauthenticated TCP client that does not send a handshake response within `connect_timeout` seconds must receive an error/close, as in MySQL. If TiDB does not support the timeout, `SET GLOBAL connect_timeout` must fail explicitly instead of reporting a value that the handshake path ignores.
### 3. What did you see instead (Required)
TiDB: SET GLOBAL connect_timeout=2; @@global.connect_timeout=2; raw socket reads 112-byte initial handshake; after 12.5s the socket is still open. MySQL 8.3 control: initial handshake 77 bytes; after 3.5s an error packet (54 bytes) is received and the peer closes.
### 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:48 registers connect_timeout as a noop variable
- pkg/server/conn.go:333-357 handshake writes the initial packet and then reads the client response with no pre-auth deadline
- pkg/server/internal/packetio.go:136-146 read deadlines are only set after PacketIO.SetReadTimeout is called; pkg/server/conn.go:1224 calls it only in the post-authentication command loop
- no pkg/server path reads connect_timeout
Contributor guide
Research direction
Start with pkg/sessionctx/variable/noop.go:48 and trace connect_timeout usage in pkg/server/conn.go:333-357 and pkg/server/internal/packetio.go:136-146. Reproduce the raw TCP probe, then compare the pre-auth handshake path with conn.go:1224, where the post-authentication read timeout is set. Done means stalled unauthenticated clients are closed after the configured timeout, or unsupported configuration is rejected explicitly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, mysql
- Domain
- backend, databases, networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100