[{"data":1,"prerenderedAt":723},["ShallowReactive",2],{"page-\u002Fasync-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002Fsetting-up-asyncpg-connection-pool-size-for-high-concurrency\u002F":3},{"id":4,"title":5,"body":6,"description":716,"extension":717,"meta":718,"navigation":135,"path":719,"seo":720,"stem":721,"__hash__":722},"content\u002Fasync-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002Fsetting-up-asyncpg-connection-pool-size-for-high-concurrency\u002Findex.md","Setting Up asyncpg Connection Pool Size for High Concurrency",{"type":7,"value":8,"toc":709},"minimark",[9,13,43,48,76,463,467,502,506,584,588,659,663,679,699,705],[10,11,5],"h1",{"id":12},"setting-up-asyncpg-connection-pool-size-for-high-concurrency",[14,15,16,17,21,22,25,26,28,29,32,33,36,37,42],"p",{},"Set ",[18,19,20],"code",{},"pool_size"," to 2–3× the CPU core count for CPU-bound async workloads. Configure ",[18,23,24],{},"max_overflow"," at 10–20% of ",[18,27,20],{}," to absorb traffic spikes without exhausting PostgreSQL ",[18,30,31],{},"max_connections",". Enable ",[18,34,35],{},"pool_pre_ping=True"," to validate connections before checkout and prevent stale socket errors. Review baseline initialization patterns in ",[38,39,41],"a",{"href":40},"\u002Fasync-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002F","Configuring Async Engines and Connection Pools"," before deploying to production.",[44,45,47],"h2",{"id":46},"exact-syntax-for-sqlalchemy-20-async-engine","Exact Syntax for SQLAlchemy 2.0 Async Engine",[14,49,50,51,54,55,57,58,57,60,63,64,67,68,71,72,75],{},"Use ",[18,52,53],{},"create_async_engine()"," with explicit ",[18,56,20],{},", ",[18,59,24],{},[18,61,62],{},"pool_timeout",", and ",[18,65,66],{},"pool_recycle"," kwargs. Pass ",[18,69,70],{},"dialect_options"," to reduce query parsing overhead and ensure ",[18,73,74],{},"echo=False"," in production to eliminate I\u002FO bottlenecks from query logging.",[77,78,83],"pre",{"className":79,"code":80,"language":81,"meta":82,"style":82},"language-python shiki shiki-themes github-light github-dark","from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession\nfrom sqlalchemy import text\nfrom typing import AsyncGenerator\n\n# High-Concurrency asyncpg Engine Initialization\nengine = create_async_engine(\n \"postgresql+asyncpg:\u002F\u002Fuser:pass@host:5432\u002Fdb\",\n pool_size=32,\n max_overflow=8,\n pool_timeout=30,\n pool_recycle=1800,\n pool_pre_ping=True,\n echo=False,\n connect_args={\n \"command_timeout\": 10,\n \"server_settings\": {\"jit\": \"off\", \"statement_timeout\": \"30000\"}\n },\n dialect_options={\"asyncpg\": {\"prepared_statement_cache_size\": 100}}\n)\n\n# Safe AsyncSession Context Management\nAsyncSessionLocal = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)\n\nasync def execute_query() -> int:\n async with AsyncSessionLocal() as session:\n async with session.begin():\n result = await session.execute(text(\"SELECT 1\"))\n return result.scalar_one()\n","python","",[18,84,85,104,117,130,137,144,156,166,181,194,207,220,233,246,257,271,301,307,334,340,345,351,379,384,406,424,434,454],{"__ignoreMap":82},[86,87,90,94,98,101],"span",{"class":88,"line":89},"line",1,[86,91,93],{"class":92},"szBVR","from",[86,95,97],{"class":96},"sVt8B"," sqlalchemy.ext.asyncio ",[86,99,100],{"class":92},"import",[86,102,103],{"class":96}," create_async_engine, async_sessionmaker, AsyncSession\n",[86,105,107,109,112,114],{"class":88,"line":106},2,[86,108,93],{"class":92},[86,110,111],{"class":96}," sqlalchemy ",[86,113,100],{"class":92},[86,115,116],{"class":96}," text\n",[86,118,120,122,125,127],{"class":88,"line":119},3,[86,121,93],{"class":92},[86,123,124],{"class":96}," typing ",[86,126,100],{"class":92},[86,128,129],{"class":96}," AsyncGenerator\n",[86,131,133],{"class":88,"line":132},4,[86,134,136],{"emptyLinePlaceholder":135},true,"\n",[86,138,140],{"class":88,"line":139},5,[86,141,143],{"class":142},"sJ8bj","# High-Concurrency asyncpg Engine Initialization\n",[86,145,147,150,153],{"class":88,"line":146},6,[86,148,149],{"class":96},"engine ",[86,151,152],{"class":92},"=",[86,154,155],{"class":96}," create_async_engine(\n",[86,157,159,163],{"class":88,"line":158},7,[86,160,162],{"class":161},"sZZnC"," \"postgresql+asyncpg:\u002F\u002Fuser:pass@host:5432\u002Fdb\"",[86,164,165],{"class":96},",\n",[86,167,169,173,175,179],{"class":88,"line":168},8,[86,170,172],{"class":171},"s4XuR"," pool_size",[86,174,152],{"class":92},[86,176,178],{"class":177},"sj4cs","32",[86,180,165],{"class":96},[86,182,184,187,189,192],{"class":88,"line":183},9,[86,185,186],{"class":171}," max_overflow",[86,188,152],{"class":92},[86,190,191],{"class":177},"8",[86,193,165],{"class":96},[86,195,197,200,202,205],{"class":88,"line":196},10,[86,198,199],{"class":171}," pool_timeout",[86,201,152],{"class":92},[86,203,204],{"class":177},"30",[86,206,165],{"class":96},[86,208,210,213,215,218],{"class":88,"line":209},11,[86,211,212],{"class":171}," pool_recycle",[86,214,152],{"class":92},[86,216,217],{"class":177},"1800",[86,219,165],{"class":96},[86,221,223,226,228,231],{"class":88,"line":222},12,[86,224,225],{"class":171}," pool_pre_ping",[86,227,152],{"class":92},[86,229,230],{"class":177},"True",[86,232,165],{"class":96},[86,234,236,239,241,244],{"class":88,"line":235},13,[86,237,238],{"class":171}," echo",[86,240,152],{"class":92},[86,242,243],{"class":177},"False",[86,245,165],{"class":96},[86,247,249,252,254],{"class":88,"line":248},14,[86,250,251],{"class":171}," connect_args",[86,253,152],{"class":92},[86,255,256],{"class":96},"{\n",[86,258,260,263,266,269],{"class":88,"line":259},15,[86,261,262],{"class":161}," \"command_timeout\"",[86,264,265],{"class":96},": ",[86,267,268],{"class":177},"10",[86,270,165],{"class":96},[86,272,274,277,280,283,285,288,290,293,295,298],{"class":88,"line":273},16,[86,275,276],{"class":161}," \"server_settings\"",[86,278,279],{"class":96},": {",[86,281,282],{"class":161},"\"jit\"",[86,284,265],{"class":96},[86,286,287],{"class":161},"\"off\"",[86,289,57],{"class":96},[86,291,292],{"class":161},"\"statement_timeout\"",[86,294,265],{"class":96},[86,296,297],{"class":161},"\"30000\"",[86,299,300],{"class":96},"}\n",[86,302,304],{"class":88,"line":303},17,[86,305,306],{"class":96}," },\n",[86,308,310,313,315,318,321,323,326,328,331],{"class":88,"line":309},18,[86,311,312],{"class":171}," dialect_options",[86,314,152],{"class":92},[86,316,317],{"class":96},"{",[86,319,320],{"class":161},"\"asyncpg\"",[86,322,279],{"class":96},[86,324,325],{"class":161},"\"prepared_statement_cache_size\"",[86,327,265],{"class":96},[86,329,330],{"class":177},"100",[86,332,333],{"class":96},"}}\n",[86,335,337],{"class":88,"line":336},19,[86,338,339],{"class":96},")\n",[86,341,343],{"class":88,"line":342},20,[86,344,136],{"emptyLinePlaceholder":135},[86,346,348],{"class":88,"line":347},21,[86,349,350],{"class":142},"# Safe AsyncSession Context Management\n",[86,352,354,357,359,362,365,367,370,373,375,377],{"class":88,"line":353},22,[86,355,356],{"class":96},"AsyncSessionLocal ",[86,358,152],{"class":92},[86,360,361],{"class":96}," async_sessionmaker(engine, ",[86,363,364],{"class":171},"class_",[86,366,152],{"class":92},[86,368,369],{"class":96},"AsyncSession, ",[86,371,372],{"class":171},"expire_on_commit",[86,374,152],{"class":92},[86,376,243],{"class":177},[86,378,339],{"class":96},[86,380,382],{"class":88,"line":381},23,[86,383,136],{"emptyLinePlaceholder":135},[86,385,387,390,393,397,400,403],{"class":88,"line":386},24,[86,388,389],{"class":92},"async",[86,391,392],{"class":92}," def",[86,394,396],{"class":395},"sScJk"," execute_query",[86,398,399],{"class":96},"() -> ",[86,401,402],{"class":177},"int",[86,404,405],{"class":96},":\n",[86,407,409,412,415,418,421],{"class":88,"line":408},25,[86,410,411],{"class":92}," async",[86,413,414],{"class":92}," with",[86,416,417],{"class":96}," AsyncSessionLocal() ",[86,419,420],{"class":92},"as",[86,422,423],{"class":96}," session:\n",[86,425,427,429,431],{"class":88,"line":426},26,[86,428,411],{"class":92},[86,430,414],{"class":92},[86,432,433],{"class":96}," session.begin():\n",[86,435,437,440,442,445,448,451],{"class":88,"line":436},27,[86,438,439],{"class":96}," result ",[86,441,152],{"class":92},[86,443,444],{"class":92}," await",[86,446,447],{"class":96}," session.execute(text(",[86,449,450],{"class":161},"\"SELECT 1\"",[86,452,453],{"class":96},"))\n",[86,455,457,460],{"class":88,"line":456},28,[86,458,459],{"class":92}," return",[86,461,462],{"class":96}," result.scalar_one()\n",[44,464,466],{"id":465},"dynamic-sizing-based-on-workload-metrics","Dynamic Sizing Based on Workload Metrics",[14,468,469,470,473,474,477,478,480,481,484,485,488,489,492,493,496,497,501],{},"Pool sizing is not static. Monitor ",[18,471,472],{},"pg_stat_activity"," for ",[18,475,476],{},"waiting"," states; increase ",[18,479,20],{}," if ",[18,482,483],{},"count(*)"," consistently hits ",[18,486,487],{},"pool_size + max_overflow",". Track application-level ",[18,490,491],{},"QueuePool"," checkout latency; values exceeding ",[18,494,495],{},"50ms"," indicate pool starvation and require immediate scaling or query optimization. Align pool architecture with overarching async patterns documented in ",[38,498,500],{"href":499},"\u002Fasync-engines-dialects-and-connection-pooling\u002F","Async Engines, Dialects, and Connection Pooling"," to ensure consistent event loop utilization.",[44,503,505],{"id":504},"error-resolution-connection-pool-exhaustion","Error Resolution: Connection Pool Exhaustion",[507,508,509,525],"table",{},[510,511,512],"thead",{},[513,514,515,519,522],"tr",{},[516,517,518],"th",{},"Error Context",[516,520,521],{},"Root Cause",[516,523,524],{},"Production Fix",[526,527,528,549,569],"tbody",{},[513,529,530,536,539],{},[531,532,533],"td",{},[18,534,535],{},"TimeoutError: QueuePool limit of size X reached",[531,537,538],{},"Checkout queue blocked by long-running transactions or undersized pool.",[531,540,541,542,544,545,548],{},"Increase ",[18,543,62],{}," temporarily, but prioritize optimizing transaction scope. Implement connection-level statement timeouts via ",[18,546,547],{},"server_settings",".",[513,550,551,556,559],{},[531,552,553],{},[18,554,555],{},"asyncpg.exceptions.ConnectionDoesNotExistError",[531,557,558],{},"Cloud load balancers or RDS proxies silently drop idle TCP sockets.",[531,560,561,562,564,565,568],{},"Lower ",[18,563,66],{}," below the provider's idle timeout threshold (typically ",[18,566,567],{},"900–1200s","). Enable OS-level TCP keepalives.",[513,570,571,574,577],{},[531,572,573],{},"Thundering Herd on Startup",[531,575,576],{},"Sudden traffic spike exhausts pool before connections establish.",[531,578,579,580,583],{},"Implement exponential backoff with jitter on connection checkout failures. Pre-warm the pool using ",[18,581,582],{},"engine.connect()"," during application startup.",[44,585,587],{"id":586},"critical-pitfalls-best-practices","Critical Pitfalls & Best Practices",[589,590,591,614,632,645],"ul",{},[592,593,594,600,601,603,604,606,607,610,611,548],"li",{},[595,596,597,598],"strong",{},"Exceeding ",[18,599,31],{},": Setting ",[18,602,20],{}," > PostgreSQL ",[18,605,31],{}," triggers ",[18,608,609],{},"FATAL: too many connections for role",". Always calculate ",[18,612,613],{},"(pool_size + max_overflow) * worker_count \u003C max_connections",[592,615,616,621,622,624,625,628,629,631],{},[595,617,618,619],{},"Missing ",[18,620,66],{},": Omitting ",[18,623,66],{}," causes ",[18,626,627],{},"ConnectionResetError"," when infrastructure drops idle TCP sockets. Always set it to ",[18,630,217],{}," or lower.",[592,633,634,637,638,641,642,548],{},[595,635,636],{},"Async Session Misconfiguration",": Using ",[18,639,640],{},"expire_on_commit=True"," in async sessions forces unnecessary database round-trips on subsequent attribute access. Always set ",[18,643,644],{},"expire_on_commit=False",[592,646,647,650,651,654,655,658],{},[595,648,649],{},"Unmanaged Transactions",": Failing to wrap ",[18,652,653],{},"session.execute()"," in ",[18,656,657],{},"async with session.begin()"," leaves transactions open, blocking pool return and causing silent connection leaks.",[44,660,662],{"id":661},"frequently-asked-questions","Frequently Asked Questions",[14,664,665,668,669,672,673,675,676,548],{},[595,666,667],{},"How do I calculate the exact asyncpg pool_size for my workload?","\nUse the baseline formula: ",[18,670,671],{},"pool_size = (CPU_cores * 2) + disk_spindle_count",". Validate empirically by monitoring ",[18,674,472],{}," and adjusting until connection wait time consistently drops below ",[18,677,678],{},"10ms",[14,680,681,688,689,692,693,695,696,698],{},[595,682,683,684,687],{},"Why does asyncpg throw ",[18,685,686],{},"ConnectionDoesNotExistError"," under load?","\nThe underlying TCP socket was terminated by a firewall, proxy, or PostgreSQL ",[18,690,691],{},"tcp_keepalives_idle"," setting. Lower ",[18,694,66],{}," to ",[18,697,567],{}," and enable OS-level keepalives to maintain socket liveness.",[14,700,701,704],{},[595,702,703],{},"Can I share a single asyncpg pool across multiple FastAPI workers?","\nNo. Each Uvicorn\u002FGunicorn worker runs in a separate process and requires its own engine instance. Pool size must be scaled per-worker, not globally, to prevent cross-process connection state corruption.",[706,707,708],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":82,"searchDepth":106,"depth":106,"links":710},[711,712,713,714,715],{"id":46,"depth":106,"text":47},{"id":465,"depth":106,"text":466},{"id":504,"depth":106,"text":505},{"id":586,"depth":106,"text":587},{"id":661,"depth":106,"text":662},"Set pool_size to 2–3× the CPU core count for CPU-bound async workloads. Configure max_overflow at 10–20% of pool_size to absorb traffic spikes without exhausting PostgreSQL max_connections. Enable pool_pre_ping=True to validate connections before checkout and prevent stale socket errors. Review baseline initialization patterns in Configuring Async Engines and Connection Pools before deploying to production.","md",{},"\u002Fasync-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002Fsetting-up-asyncpg-connection-pool-size-for-high-concurrency",{"title":5,"description":716},"async-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002Fsetting-up-asyncpg-connection-pool-size-for-high-concurrency\u002Findex","mBLIcNRnnbvGtfbCRF2R8uI7gN-0_tKqCwygYxabBaA",1778149144400]