An API request times out after ten seconds and returns an error to the user. Everyone assumes the work stopped.
It did not. The database is still executing that query, still holding a connection, still consuming CPU and I/O, and still blocking whatever its locks block. It will run to completion and discard the result, because nobody told it the client had gone.
At scale that is a meaningful waste, and during an incident it is worse — a wave of timed-out requests leaves a wave of orphaned queries competing with the retries.
What changed in 2026
- Driver cancellation support improved. More database clients cancel automatically on context cancellation rather than merely abandoning the connection.
- Server-side timeouts became the recommended backstop. Reliance on client-side timeouts alone was recognised as insufficient.
- Pooler behaviour got attention. How connection poolers handle abandoned connections became a documented consideration.
- Context propagation spread. Passing cancellation context down to the database call became standard in frameworks that support it.
Why the query keeps running
The database protocol is request-response over a connection. Once a query is sent, that connection is busy carrying the query and eventually its result. There is no channel on it to say "stop".
So cancellation is a separate request on a separate connection. The client opens a new connection, identifies the session running the query, and asks the server to cancel it. Only then does the server know.
If the client simply closes its connection instead, the server may not notice immediately. Detecting a dropped connection typically happens when the server next tries to write, which for a long-running query is not until it produces a result.
This is why a client-side timeout alone is insufficient: it stops the client waiting, and does nothing on the server.
| Client action |
Server effect |
| Waits for the result |
Query runs |
| Times out and returns |
Query still runs |
| Closes the connection |
Query runs until the server notices |
| Sends a cancel request |
Query stops at the next check |
| Server statement timeout fires |
Query stops |
Cancellation is cooperative
Even a proper cancel request is not instantaneous. The server checks for cancellation at intervals during execution, so a query in the middle of a long operation may take a moment to notice.
There is also work after the stop. A cancelled statement that modified rows must have those changes undone, and rolling back a large partially-complete operation takes time proportional to what it did. Cancelling a huge update does not free resources immediately.
Cancelling versus terminating is a distinction worth knowing. Cancel stops the current statement and leaves the session usable. Terminate ends the whole session, dropping the connection and rolling back the transaction. Terminate is heavier and appropriate when the session is stuck or idle in a transaction, rather than merely running a slow query.
Server-side timeouts are the reliable answer
Because cancellation depends on the client doing something, and clients crash, lose network, and are written by people who did not think about this, the reliable protection is server-side.
A statement timeout ends the query regardless of what the client does or fails to do — see statement timeouts. An idle-in-transaction timeout handles the session that stopped talking mid-transaction.
The complete picture is layered: client timeout so the user gets a response, client-side cancellation so the server learns quickly, and server-side timeouts as the backstop that works when the other two do not.
Connection poolers add a wrinkle. A pooler may return an abandoned connection to the pool while its query is still executing, handing it to another request. Whether your pooler cancels, drains, or discards such connections is worth confirming — see connection pooling explained.
Common mistakes
- Client timeout with no cancellation. Query runs on regardless.
- No server-side timeout. Nothing stops an orphaned query.
- Assuming closing the connection cancels. The server may not notice for a long time.
- Terminating when cancelling would do. Drops the session unnecessarily.
- Not propagating cancellation context. Frameworks support it; code frequently does not use it.
- Expecting instant cancellation. It is cooperative, and rollback takes time.
FAQ
Does my driver cancel automatically?
Many modern drivers do when a request context is cancelled, and this varies. Check your specific driver rather than assuming, and test it — the behaviour is easy to verify.
Can I cancel someone else's query?
With appropriate permissions, yes — engines expose functions to cancel or terminate a session by identifier. Useful during an incident when a specific query is blocking others.
Is cancelling safe mid-transaction?
The statement is rolled back and the transaction remains open in a failed state, so the client must roll back or use a savepoint — see savepoints.
What about read-only queries?
Nothing to roll back, so cancellation is cleaner and faster. The resource waste before cancellation is the same.
Where to go next
For the server-side backstop, read statement timeouts. For pooler behaviour with abandoned connections, connection pooling explained, and for recovering within a transaction, savepoints.