Discard MySQL Async Connections After Query Cancellation

Cancelling the Python task that awaits a database query does not necessarily cancel the command already executing on MySQL or drain its response. Reusing that connection immediately can let unread protocol data contaminate the next operation. Close the connection after cancellation.

Last updated: November 5, 2026.

import asyncio
from mysql.connector.aio import connect

async def run_with_timeout(config, sql, params=()):
    connection = await connect(**config)
    cursor = await connection.cursor()
    try:
        async with asyncio.timeout(2):
            await cursor.execute(sql, params)
            return await cursor.fetchall()
    except (TimeoutError, asyncio.CancelledError):
        # Do not return this connection to normal use.
        await connection.close()
        raise
    finally:
        if connection.is_connected():
            await cursor.close()
            await connection.close()

When a pool owns the connection, invalidate or discard it through the pool’s supported API rather than returning it as healthy. A fresh physical connection is safer than guessing whether the old response was fully drained.

Cancellation is a protocol boundary

The official Connector/Python asyncio guide shows that query execution, result fetching, cursor closing, and connection closing are separate awaited operations. Cancelling one await interrupts the client task, but the server may still finish and send a result on the same socket.

A current Connector/Python report demonstrates the dangerous symptom: after cancelling an in-flight query, a later query can receive the earlier result and column metadata. Until the installed connector version has a verified fix, treat cancellation or timeout during I/O as connection-fatal.

Make pool behavior explicit

Python’s task-cancellation documentation explains that CancelledError is raised at the next opportunity and should normally be propagated after cleanup. Catch it only long enough to discard the database resource, then re-raise it.

Test with a controlled slow query, cancel after the server sees it, and issue a sentinel query through the next checked-out connection. Assert the exact columns and values, not merely a successful status. Track cancellations, forced disconnects, and pool replacement failures.

Use server-side statement timeouts where available so the database also stops expensive work. Client cancellation still needs cleanup because network timing can race with the server response. Continue with MySQL connection limits, recovering failed MySQL connections, and reading database error details.

Related Web Cheat Sheet guides

Sergey Kornilov

Sergey Kornilov