pingcap / pingcap/tidb

server: short autocommit DML may commit after client disconnect

Open
#69,910 2 comments 0 reactions 0 assignees View on GitHub
may-affects-7.5 may-affects-8.1 may-affects-8.5 severity/major sig/sql-infra type/bug
Dominant language
Go
Stars
40.5k
Forks
6.2k
PR merge metrics
PR metrics pending

Description

## Bug Report

### 1. Minimal reproduce step (Required)

This is a regression related to #68236. The original issue was fixed by #68237/#68481, but #69068 added a one-second threshold that allows short autocommit DML to miss the client-disconnect check.

1. Start TiDB and connect with a MySQL-compatible client. Use a second connection for observation.

2. Create a test table:

```sql
DROP TABLE IF EXISTS test.t_disconnect_short;
CREATE TABLE test.t_disconnect_short (
id INT PRIMARY KEY,
v INT
);
```

3. From a shell, start a short autocommit INSERT:

```bash
mysql --protocol=tcp -h -P -uroot \\
-e "INSERT INTO test.t_disconnect_short VALUES (1, SLEEP(0.3));" &
pid=$!
```

4. After the INSERT appears in `information_schema.processlist`, force-close only the client process:

```bash
kill -KILL "$pid"
wait "$pid" 2>/dev/null || true
sleep 1
```

5. Query the table from the observation connection:

```sql
SELECT * FROM test.t_disconnect_short;
```

As a control, repeat the same test with `SLEEP(2)` instead of `SLEEP(0.3)`.

### 2. What did you expect to see? (Required)

After the client connection is closed during execution, the autocommit DML should be interrupted and rolled back. The table should contain zero rows.

### 3. What did you see instead (Required)

With `SLEEP(0.3)`, the client connection is closed while the statement is running, but the INSERT is still committed. The table contains:

```text
id v
1 0
```

This was reproduced on a local TiDB v8.5.7 instance after confirming that the INSERT was present in `information_schema.processlist` before killing the client. The `SLEEP(2)` control case leaves zero rows.

This can make the client observe a connection failure or unknown outcome while the write has already committed; retrying the request may then cause duplicate writes.

### 4. What is your TiDB version? (Required)

```text
Release Version: v8.5.7
Edition: Community
Git Commit Hash: 202b7f47286a1109b5c957401d34c9358d130ae0
Git Branch: HEAD
UTC Build Time: 2026-07-07 08:10:56
GoVersion: go1.25.10
Race Enabled: false
Check Table Before Drop: false
Store: tikv
```

Relevant code path: `finishStmt` skips the immediate connection-alive check when the statement has run for less than one second, while `SQLKiller.HandleSignal` throttles connection probes to one second in production. Therefore, short statements can reach commit without observing the closed client socket.

Contributor guide

Open the contributing guide

Research direction

Start by reading finishStmt and SQLKiller.HandleSignal, the code paths identified in the report. Reproduce the short-SLEEP and long-SLEEP disconnect cases, then verify that a client disconnect during short autocommit DML interrupts execution and leaves zero rows committed.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, sql
Domain
databases, distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.