必须显式调用 await client.close() 才能释放连接,因 AsyncIOMotorClient 未实现 __aenter__/__aexit__,不支持 async with;且 close() 是协程,不 await 则无效,需在应用生命周期末尾统一关闭。

必须显式调用 client.close(),否则连接不会自动释放,长期运行的服务会出现连接泄漏。
为什么 AsyncIOMotorClient 不支持 async with 自动关闭
Motor 的 AsyncIOMotorClient 类没有实现 __aenter__ 和 __aexit__,所以不能像 aiohttp.ClientSession 那样用 async with 包裹。直接写 async with client: 会报 AttributeError: __aexit__。
- 官方文档明确说明:客户端对象需手动关闭,无上下文管理器支持
- 即使所有
AsyncIOMotorCollection或AsyncIOMotorDatabase引用都已销毁,client实例仍保有底层连接池 - 常见误判:“我只用了
db.collection.find(),没存 client 引用”——但只要 client 对象还存活(比如定义在模块顶层或类属性中),连接就一直挂着
client.close() 必须 await,且不能漏掉
client.close() 是一个协程函数,不是普通方法。不加 await 只是创建了一个未执行的协程对象,连接照常保持活跃。
- 错误写法:
client.close()(无 await)→ 连接未关闭,日志里看不到任何提示 - 正确写法:
await client.close() - 如果在
finally块里调用,也要确保该finally所在的函数本身是async,且await被执行到 - 多个并发任务共用一个 client 时,只能在所有任务结束后调一次
await client.close();提前关会导致其他任务抛InvalidOperation: Cannot use connection after it has been closed
典型生命周期管理结构(推荐模式)
把 client 创建和关闭绑定到应用主事件循环的启停阶段,而不是每次请求都新建/关闭——后者开销大且易出错。
立即学习“Python免费学习笔记(深入)”;
- FastAPI 中应在
startup事件创建 client,在shutdown事件中await client.close() - 纯脚本场景下,用
asyncio.run()包裹主函数,并在最后await client.close(),例如:
import asyncio
from motor.motor_asyncio import AsyncIOMotorClient
<p>async def main():
client = AsyncIOMotorClient("mongodb://localhost:27017")
db = client["test"]
await db.test.insert_one({"x": 1})
await client.close() # ← 关键:必须 await,且放在这里</p><p>asyncio.run(main())- 切忌在中间某个
async def里单独await client.close(),除非你 100% 确认后续再无任何数据库操作
最容易被忽略的一点:client.close() 之后,所有基于它的 database、collection 对象都不可再用——哪怕只是调 collection.name 都可能触发连接重试或静默失败,调试时很难定位。



















