The problem is straightforward to state and surprisingly hard to solve correctly. Celery workers are synchronous. Celery spawns prefork worker processes, and when a task arrives, it calls your task function like this: task_function(*args, **kwargs) . It expects a return value. It blocks the worker thread until it gets one. It does not know or care that you wrote async def . But modern Python services are async. FastAPI is async. SQLAlchemy 2.0 is async. httpx, aiohttp, asyncpg the entire...