[{"data":1,"prerenderedAt":2379},["ShallowReactive",2],{"page-\u002Fasync-engines-dialects-and-connection-pooling\u002Ftuning-connection-pools-for-cloud-databases\u002Fsetting-pool-size-and-max-overflow-for-aws-rds\u002F":3},{"id":4,"title":5,"body":6,"description":2371,"extension":2372,"meta":2373,"navigation":108,"path":2375,"seo":2376,"stem":2377,"__hash__":2378},"content\u002Fasync-engines-dialects-and-connection-pooling\u002Ftuning-connection-pools-for-cloud-databases\u002Fsetting-pool-size-and-max-overflow-for-aws-rds\u002Findex.md","Setting pool_size and max_overflow for AWS RDS",{"type":7,"value":8,"toc":2354},"minimark",[9,13,36,41,62,68,183,188,508,515,519,524,527,546,550,565,568,907,913,917,924,1204,1221,1225,1241,1250,1254,1445,1449,1456,1463,1802,1805,1809,1812,1819,2226,2244,2248,2263,2278,2297,2308,2312,2350],[10,11,5],"h1",{"id":12},"setting-pool_size-and-max_overflow-for-aws-rds",[14,15,16,17,21,22,25,26,29,30,35],"p",{},"Set ",[18,19,20],"code",{},"pool_size = floor((rds_max_connections - reserved) \u002F instance_count * 0.7)"," and ",[18,23,24],{},"max_overflow = floor(pool_size \u002F 2)",", then verify that ",[18,27,28],{},"(pool_size + max_overflow) * instance_count"," never exceeds the usable connection budget — this is the core formula for safe RDS pool sizing, and the full derivation with cloud-specific context lives in ",[31,32,34],"a",{"href":33},"\u002Fasync-engines-dialects-and-connection-pooling\u002Ftuning-connection-pools-for-cloud-databases\u002F","Tuning Connection Pools for Cloud Databases",".",[37,38,40],"h2",{"id":39},"quick-answer","Quick Answer",[14,42,43,44,47,48,51,52,55,56,21,59,35],{},"RDS ",[18,45,46],{},"max_connections"," is derived from instance RAM, not a configurable static value. The authoritative number is available from ",[18,49,50],{},"SHOW max_connections;"," connected to the instance. The formula AWS uses internally is approximately ",[18,53,54],{},"LEAST(DBInstanceClassMemory \u002F 9531392, 5000)",". Subtract a fixed reserve for the superuser, administrative sessions, and monitoring agents, then divide the remainder evenly across all application instances. Apply a 70\u002F30 split between ",[18,57,58],{},"pool_size",[18,60,61],{},"max_overflow",[14,63,64],{},[65,66,67],"strong",{},"Before:",[69,70,75],"pre",{"className":71,"code":72,"language":73,"meta":74,"style":74},"language-python shiki shiki-themes github-light github-dark","# Legacy \u002F unsafe — pool_size is a guess, no instance-count accounting\nfrom sqlalchemy import create_engine\n\nengine = create_engine(\n    \"postgresql+psycopg2:\u002F\u002Fapp:secret@mydb.us-east-1.rds.amazonaws.com\u002Forders\",\n    pool_size=100,       # ← arbitrary, does not account for multiple instances\n    max_overflow=20,\n    pool_pre_ping=False,\n)\n","python","",[18,76,77,86,103,110,122,132,151,164,177],{"__ignoreMap":74},[78,79,82],"span",{"class":80,"line":81},"line",1,[78,83,85],{"class":84},"sJ8bj","# Legacy \u002F unsafe — pool_size is a guess, no instance-count accounting\n",[78,87,89,93,97,100],{"class":80,"line":88},2,[78,90,92],{"class":91},"szBVR","from",[78,94,96],{"class":95},"sVt8B"," sqlalchemy ",[78,98,99],{"class":91},"import",[78,101,102],{"class":95}," create_engine\n",[78,104,106],{"class":80,"line":105},3,[78,107,109],{"emptyLinePlaceholder":108},true,"\n",[78,111,113,116,119],{"class":80,"line":112},4,[78,114,115],{"class":95},"engine ",[78,117,118],{"class":91},"=",[78,120,121],{"class":95}," create_engine(\n",[78,123,125,129],{"class":80,"line":124},5,[78,126,128],{"class":127},"sZZnC","    \"postgresql+psycopg2:\u002F\u002Fapp:secret@mydb.us-east-1.rds.amazonaws.com\u002Forders\"",[78,130,131],{"class":95},",\n",[78,133,135,139,141,145,148],{"class":80,"line":134},6,[78,136,138],{"class":137},"s4XuR","    pool_size",[78,140,118],{"class":91},[78,142,144],{"class":143},"sj4cs","100",[78,146,147],{"class":95},",       ",[78,149,150],{"class":84},"# ← arbitrary, does not account for multiple instances\n",[78,152,154,157,159,162],{"class":80,"line":153},7,[78,155,156],{"class":137},"    max_overflow",[78,158,118],{"class":91},[78,160,161],{"class":143},"20",[78,163,131],{"class":95},[78,165,167,170,172,175],{"class":80,"line":166},8,[78,168,169],{"class":137},"    pool_pre_ping",[78,171,118],{"class":91},[78,173,174],{"class":143},"False",[78,176,131],{"class":95},[78,178,180],{"class":80,"line":179},9,[78,181,182],{"class":95},")\n",[14,184,185],{},[65,186,187],{},"After — SQLAlchemy 2.0 async with derived values:",[69,189,191],{"className":71,"code":190,"language":73,"meta":74,"style":74},"from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession\n\n# Inputs (replace with your actuals):\nRDS_MAX_CONNECTIONS = 683        # db.r6g.large: LEAST(17179869184 \u002F 9531392, 5000)\nSUPERUSER_RESERVED = 3           # superuser_reserved_connections default\nADMIN_RESERVE = 10               # monitoring agent, Alembic, interactive psql\nAPP_INSTANCE_COUNT = 4           # e.g. 4 ECS tasks \u002F Kubernetes pods\n\nusable = RDS_MAX_CONNECTIONS - SUPERUSER_RESERVED - ADMIN_RESERVE  # = 670\nper_instance = usable \u002F\u002F APP_INSTANCE_COUNT                          # = 167\npool_size    = int(per_instance * 0.7)                               # = 116\nmax_overflow = int(per_instance * 0.3)                               # = 50\n\nengine = create_async_engine(\n    \"postgresql+asyncpg:\u002F\u002Fapp:secret@mydb.cluster-xyz.us-east-1.rds.amazonaws.com\u002Forders\",\n    pool_size=pool_size,\n    max_overflow=max_overflow,\n    pool_timeout=30.0,\n    pool_recycle=1800,        # 30 min — RDS default idle timeout is 8 h\n    pool_pre_ping=True,\n    echo=False,\n)\n\nAsyncSessionLocal = async_sessionmaker(\n    engine, class_=AsyncSession, expire_on_commit=False\n)\n",[18,192,193,205,209,214,228,241,254,267,271,295,315,341,363,368,378,386,396,406,419,436,448,460,465,470,481,503],{"__ignoreMap":74},[78,194,195,197,200,202],{"class":80,"line":81},[78,196,92],{"class":91},[78,198,199],{"class":95}," sqlalchemy.ext.asyncio ",[78,201,99],{"class":91},[78,203,204],{"class":95}," create_async_engine, async_sessionmaker, AsyncSession\n",[78,206,207],{"class":80,"line":88},[78,208,109],{"emptyLinePlaceholder":108},[78,210,211],{"class":80,"line":105},[78,212,213],{"class":84},"# Inputs (replace with your actuals):\n",[78,215,216,219,222,225],{"class":80,"line":112},[78,217,218],{"class":143},"RDS_MAX_CONNECTIONS",[78,220,221],{"class":91}," =",[78,223,224],{"class":143}," 683",[78,226,227],{"class":84},"        # db.r6g.large: LEAST(17179869184 \u002F 9531392, 5000)\n",[78,229,230,233,235,238],{"class":80,"line":124},[78,231,232],{"class":143},"SUPERUSER_RESERVED",[78,234,221],{"class":91},[78,236,237],{"class":143}," 3",[78,239,240],{"class":84},"           # superuser_reserved_connections default\n",[78,242,243,246,248,251],{"class":80,"line":134},[78,244,245],{"class":143},"ADMIN_RESERVE",[78,247,221],{"class":91},[78,249,250],{"class":143}," 10",[78,252,253],{"class":84},"               # monitoring agent, Alembic, interactive psql\n",[78,255,256,259,261,264],{"class":80,"line":153},[78,257,258],{"class":143},"APP_INSTANCE_COUNT",[78,260,221],{"class":91},[78,262,263],{"class":143}," 4",[78,265,266],{"class":84},"           # e.g. 4 ECS tasks \u002F Kubernetes pods\n",[78,268,269],{"class":80,"line":166},[78,270,109],{"emptyLinePlaceholder":108},[78,272,273,276,278,281,284,287,289,292],{"class":80,"line":179},[78,274,275],{"class":95},"usable ",[78,277,118],{"class":91},[78,279,280],{"class":143}," RDS_MAX_CONNECTIONS",[78,282,283],{"class":91}," -",[78,285,286],{"class":143}," SUPERUSER_RESERVED",[78,288,283],{"class":91},[78,290,291],{"class":143}," ADMIN_RESERVE",[78,293,294],{"class":84},"  # = 670\n",[78,296,298,301,303,306,309,312],{"class":80,"line":297},10,[78,299,300],{"class":95},"per_instance ",[78,302,118],{"class":91},[78,304,305],{"class":95}," usable ",[78,307,308],{"class":91},"\u002F\u002F",[78,310,311],{"class":143}," APP_INSTANCE_COUNT",[78,313,314],{"class":84},"                          # = 167\n",[78,316,318,321,323,326,329,332,335,338],{"class":80,"line":317},11,[78,319,320],{"class":95},"pool_size    ",[78,322,118],{"class":91},[78,324,325],{"class":143}," int",[78,327,328],{"class":95},"(per_instance ",[78,330,331],{"class":91},"*",[78,333,334],{"class":143}," 0.7",[78,336,337],{"class":95},")                               ",[78,339,340],{"class":84},"# = 116\n",[78,342,344,347,349,351,353,355,358,360],{"class":80,"line":343},12,[78,345,346],{"class":95},"max_overflow ",[78,348,118],{"class":91},[78,350,325],{"class":143},[78,352,328],{"class":95},[78,354,331],{"class":91},[78,356,357],{"class":143}," 0.3",[78,359,337],{"class":95},[78,361,362],{"class":84},"# = 50\n",[78,364,366],{"class":80,"line":365},13,[78,367,109],{"emptyLinePlaceholder":108},[78,369,371,373,375],{"class":80,"line":370},14,[78,372,115],{"class":95},[78,374,118],{"class":91},[78,376,377],{"class":95}," create_async_engine(\n",[78,379,381,384],{"class":80,"line":380},15,[78,382,383],{"class":127},"    \"postgresql+asyncpg:\u002F\u002Fapp:secret@mydb.cluster-xyz.us-east-1.rds.amazonaws.com\u002Forders\"",[78,385,131],{"class":95},[78,387,389,391,393],{"class":80,"line":388},16,[78,390,138],{"class":137},[78,392,118],{"class":91},[78,394,395],{"class":95},"pool_size,\n",[78,397,399,401,403],{"class":80,"line":398},17,[78,400,156],{"class":137},[78,402,118],{"class":91},[78,404,405],{"class":95},"max_overflow,\n",[78,407,409,412,414,417],{"class":80,"line":408},18,[78,410,411],{"class":137},"    pool_timeout",[78,413,118],{"class":91},[78,415,416],{"class":143},"30.0",[78,418,131],{"class":95},[78,420,422,425,427,430,433],{"class":80,"line":421},19,[78,423,424],{"class":137},"    pool_recycle",[78,426,118],{"class":91},[78,428,429],{"class":143},"1800",[78,431,432],{"class":95},",        ",[78,434,435],{"class":84},"# 30 min — RDS default idle timeout is 8 h\n",[78,437,439,441,443,446],{"class":80,"line":438},20,[78,440,169],{"class":137},[78,442,118],{"class":91},[78,444,445],{"class":143},"True",[78,447,131],{"class":95},[78,449,451,454,456,458],{"class":80,"line":450},21,[78,452,453],{"class":137},"    echo",[78,455,118],{"class":91},[78,457,174],{"class":143},[78,459,131],{"class":95},[78,461,463],{"class":80,"line":462},22,[78,464,182],{"class":95},[78,466,468],{"class":80,"line":467},23,[78,469,109],{"emptyLinePlaceholder":108},[78,471,473,476,478],{"class":80,"line":472},24,[78,474,475],{"class":95},"AsyncSessionLocal ",[78,477,118],{"class":91},[78,479,480],{"class":95}," async_sessionmaker(\n",[78,482,484,487,490,492,495,498,500],{"class":80,"line":483},25,[78,485,486],{"class":95},"    engine, ",[78,488,489],{"class":137},"class_",[78,491,118],{"class":91},[78,493,494],{"class":95},"AsyncSession, ",[78,496,497],{"class":137},"expire_on_commit",[78,499,118],{"class":91},[78,501,502],{"class":143},"False\n",[78,504,506],{"class":80,"line":505},26,[78,507,182],{"class":95},[14,509,510,511,514],{},"At scale-out the worst-case total is ",[18,512,513],{},"(116 + 50) × 4 = 664",", safely within the 670-connection budget.",[37,516,518],{"id":517},"execution-context-async-workflow-integration","Execution Context & Async Workflow Integration",[520,521,523],"h3",{"id":522},"why-the-formula-matters-for-async-python-specifically","Why the formula matters for async Python specifically",[14,525,526],{},"In a threaded server, each thread holds a connection for the duration of a request. Thread count is an upper bound on connection demand and is usually modest (8–32). In an async server (Uvicorn, Hypercorn), a single OS thread runs thousands of concurrent coroutines — but each coroutine still requires a real database connection while a query is in-flight. The pool controls how many simultaneous queries reach RDS.",[14,528,529,530,533,534,537,538,541,542,545],{},"With asyncpg and ",[18,531,532],{},"AsyncAdaptedQueuePool",", connection checkout is non-blocking: a coroutine that cannot immediately acquire a connection is suspended and yields control to other coroutines. This means pool exhaustion does not hang the event loop — but it does cause all waiting coroutines to accumulate timeout pressure. When ",[18,535,536],{},"pool_timeout"," expires, SQLAlchemy raises ",[18,539,540],{},"sqlalchemy.exc.TimeoutError"," (surfaced to the caller as ",[18,543,544],{},"QueuePool limit of size X overflow Y reached, connection timed out, timeout 30",").",[520,547,549],{"id":548},"scaling-pool_size-when-instance-count-changes","Scaling pool_size when instance count changes",[14,551,552,553,556,557,560,561,564],{},"Instance count changes when you autoscale. If your application scales from 4 to 8 ECS tasks, and each task still has ",[18,554,555],{},"pool_size=116, max_overflow=50",", worst-case connections jump from 664 to 1328 — nearly double ",[18,558,559],{},"max_connections=683",". The application will hit ",[18,562,563],{},"FATAL: remaining connection slots are reserved"," immediately.",[14,566,567],{},"The correct pattern is to parameterize pool sizes from an environment variable set by the deployment system:",[69,569,571],{"className":71,"code":570,"language":73,"meta":74,"style":74},"import os\nfrom sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession\n\nRDS_MAX_CONNECTIONS = int(os.environ[\"RDS_MAX_CONNECTIONS\"])        # set in task definition\nAPP_INSTANCE_COUNT  = int(os.environ[\"APP_INSTANCE_COUNT\"])         # set by autoscaler or fixed\nADMIN_RESERVE       = int(os.environ.get(\"DB_ADMIN_RESERVE\", \"15\"))\n\nusable       = RDS_MAX_CONNECTIONS - ADMIN_RESERVE\nper_instance = max(1, usable \u002F\u002F APP_INSTANCE_COUNT)\npool_size    = max(1, int(per_instance * 0.7))\nmax_overflow = max(1, int(per_instance * 0.3))\n\nengine = create_async_engine(\n    os.environ[\"DATABASE_URL\"],\n    pool_size=pool_size,\n    max_overflow=max_overflow,\n    pool_timeout=30.0,\n    pool_recycle=1800,\n    pool_pre_ping=True,\n    echo=False,\n    connect_args={\n        \"command_timeout\": 15,\n        \"server_settings\": {\"statement_timeout\": \"20000\"},\n    },\n)\n\nAsyncSessionLocal = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)\n",[18,572,573,580,590,594,614,634,658,662,676,700,725,749,753,761,772,780,788,798,808,818,828,838,851,870,875,879,883],{"__ignoreMap":74},[78,574,575,577],{"class":80,"line":81},[78,576,99],{"class":91},[78,578,579],{"class":95}," os\n",[78,581,582,584,586,588],{"class":80,"line":88},[78,583,92],{"class":91},[78,585,199],{"class":95},[78,587,99],{"class":91},[78,589,204],{"class":95},[78,591,592],{"class":80,"line":105},[78,593,109],{"emptyLinePlaceholder":108},[78,595,596,598,600,602,605,608,611],{"class":80,"line":112},[78,597,218],{"class":143},[78,599,221],{"class":91},[78,601,325],{"class":143},[78,603,604],{"class":95},"(os.environ[",[78,606,607],{"class":127},"\"RDS_MAX_CONNECTIONS\"",[78,609,610],{"class":95},"])        ",[78,612,613],{"class":84},"# set in task definition\n",[78,615,616,618,621,623,625,628,631],{"class":80,"line":124},[78,617,258],{"class":143},[78,619,620],{"class":91},"  =",[78,622,325],{"class":143},[78,624,604],{"class":95},[78,626,627],{"class":127},"\"APP_INSTANCE_COUNT\"",[78,629,630],{"class":95},"])         ",[78,632,633],{"class":84},"# set by autoscaler or fixed\n",[78,635,636,638,641,643,646,649,652,655],{"class":80,"line":134},[78,637,245],{"class":143},[78,639,640],{"class":91},"       =",[78,642,325],{"class":143},[78,644,645],{"class":95},"(os.environ.get(",[78,647,648],{"class":127},"\"DB_ADMIN_RESERVE\"",[78,650,651],{"class":95},", ",[78,653,654],{"class":127},"\"15\"",[78,656,657],{"class":95},"))\n",[78,659,660],{"class":80,"line":153},[78,661,109],{"emptyLinePlaceholder":108},[78,663,664,667,669,671,673],{"class":80,"line":166},[78,665,666],{"class":95},"usable       ",[78,668,118],{"class":91},[78,670,280],{"class":143},[78,672,283],{"class":91},[78,674,675],{"class":143}," ADMIN_RESERVE\n",[78,677,678,680,682,685,688,691,694,696,698],{"class":80,"line":179},[78,679,300],{"class":95},[78,681,118],{"class":91},[78,683,684],{"class":143}," max",[78,686,687],{"class":95},"(",[78,689,690],{"class":143},"1",[78,692,693],{"class":95},", usable ",[78,695,308],{"class":91},[78,697,311],{"class":143},[78,699,182],{"class":95},[78,701,702,704,706,708,710,712,714,717,719,721,723],{"class":80,"line":297},[78,703,320],{"class":95},[78,705,118],{"class":91},[78,707,684],{"class":143},[78,709,687],{"class":95},[78,711,690],{"class":143},[78,713,651],{"class":95},[78,715,716],{"class":143},"int",[78,718,328],{"class":95},[78,720,331],{"class":91},[78,722,334],{"class":143},[78,724,657],{"class":95},[78,726,727,729,731,733,735,737,739,741,743,745,747],{"class":80,"line":317},[78,728,346],{"class":95},[78,730,118],{"class":91},[78,732,684],{"class":143},[78,734,687],{"class":95},[78,736,690],{"class":143},[78,738,651],{"class":95},[78,740,716],{"class":143},[78,742,328],{"class":95},[78,744,331],{"class":91},[78,746,357],{"class":143},[78,748,657],{"class":95},[78,750,751],{"class":80,"line":343},[78,752,109],{"emptyLinePlaceholder":108},[78,754,755,757,759],{"class":80,"line":365},[78,756,115],{"class":95},[78,758,118],{"class":91},[78,760,377],{"class":95},[78,762,763,766,769],{"class":80,"line":370},[78,764,765],{"class":95},"    os.environ[",[78,767,768],{"class":127},"\"DATABASE_URL\"",[78,770,771],{"class":95},"],\n",[78,773,774,776,778],{"class":80,"line":380},[78,775,138],{"class":137},[78,777,118],{"class":91},[78,779,395],{"class":95},[78,781,782,784,786],{"class":80,"line":388},[78,783,156],{"class":137},[78,785,118],{"class":91},[78,787,405],{"class":95},[78,789,790,792,794,796],{"class":80,"line":398},[78,791,411],{"class":137},[78,793,118],{"class":91},[78,795,416],{"class":143},[78,797,131],{"class":95},[78,799,800,802,804,806],{"class":80,"line":408},[78,801,424],{"class":137},[78,803,118],{"class":91},[78,805,429],{"class":143},[78,807,131],{"class":95},[78,809,810,812,814,816],{"class":80,"line":421},[78,811,169],{"class":137},[78,813,118],{"class":91},[78,815,445],{"class":143},[78,817,131],{"class":95},[78,819,820,822,824,826],{"class":80,"line":438},[78,821,453],{"class":137},[78,823,118],{"class":91},[78,825,174],{"class":143},[78,827,131],{"class":95},[78,829,830,833,835],{"class":80,"line":450},[78,831,832],{"class":137},"    connect_args",[78,834,118],{"class":91},[78,836,837],{"class":95},"{\n",[78,839,840,843,846,849],{"class":80,"line":462},[78,841,842],{"class":127},"        \"command_timeout\"",[78,844,845],{"class":95},": ",[78,847,848],{"class":143},"15",[78,850,131],{"class":95},[78,852,853,856,859,862,864,867],{"class":80,"line":467},[78,854,855],{"class":127},"        \"server_settings\"",[78,857,858],{"class":95},": {",[78,860,861],{"class":127},"\"statement_timeout\"",[78,863,845],{"class":95},[78,865,866],{"class":127},"\"20000\"",[78,868,869],{"class":95},"},\n",[78,871,872],{"class":80,"line":472},[78,873,874],{"class":95},"    },\n",[78,876,877],{"class":80,"line":483},[78,878,182],{"class":95},[78,880,881],{"class":80,"line":505},[78,882,109],{"emptyLinePlaceholder":108},[78,884,886,888,890,893,895,897,899,901,903,905],{"class":80,"line":885},27,[78,887,475],{"class":95},[78,889,118],{"class":91},[78,891,892],{"class":95}," async_sessionmaker(engine, ",[78,894,489],{"class":137},[78,896,118],{"class":91},[78,898,494],{"class":95},[78,900,497],{"class":137},[78,902,118],{"class":91},[78,904,174],{"class":143},[78,906,182],{"class":95},[14,908,909,910,912],{},"Passing ",[18,911,258],{}," as an environment variable requires the deployment system to inject the desired replica count at startup rather than reading it from the database. Many teams manage this with ECS task definition environment overrides or Kubernetes downward API, setting it equal to the replica count in the deployment spec.",[520,914,916],{"id":915},"verifying-the-formula-with-pg_stat_activity","Verifying the formula with pg_stat_activity",[14,918,919,920,923],{},"After deploying, confirm actual connection counts match predictions by querying ",[18,921,922],{},"pg_stat_activity"," from a psql session or a monitoring query:",[69,925,927],{"className":71,"code":926,"language":73,"meta":74,"style":74},"from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker\nfrom sqlalchemy import text\n\ndiagnostic_engine = create_async_engine(\n    \"postgresql+asyncpg:\u002F\u002Fadmin:secret@mydb.rds.amazonaws.com\u002Forders\",\n    pool_size=1,\n    max_overflow=0,\n)\nDiagnosticSession = async_sessionmaker(diagnostic_engine, class_=AsyncSession)\n\n\nasync def check_connection_budget() -> None:\n    \"\"\"Print current active connections grouped by application name.\"\"\"\n    async with DiagnosticSession() as session:\n        result = await session.execute(\n            text(\n                \"\"\"\n                SELECT application_name,\n                       state,\n                       count(*) AS conn_count\n                FROM   pg_stat_activity\n                WHERE  datname = current_database()\n                GROUP  BY application_name, state\n                ORDER  BY conn_count DESC;\n                \"\"\"\n            )\n        )\n        for row in result:\n            print(f\"{row.application_name!r:40s}  state={row.state!r:15s}  count={row.conn_count}\")\n",[18,928,929,940,951,955,964,971,981,992,996,1013,1017,1021,1042,1047,1064,1077,1082,1087,1092,1097,1102,1107,1112,1117,1122,1126,1131,1136,1151],{"__ignoreMap":74},[78,930,931,933,935,937],{"class":80,"line":81},[78,932,92],{"class":91},[78,934,199],{"class":95},[78,936,99],{"class":91},[78,938,939],{"class":95}," AsyncSession, create_async_engine, async_sessionmaker\n",[78,941,942,944,946,948],{"class":80,"line":88},[78,943,92],{"class":91},[78,945,96],{"class":95},[78,947,99],{"class":91},[78,949,950],{"class":95}," text\n",[78,952,953],{"class":80,"line":105},[78,954,109],{"emptyLinePlaceholder":108},[78,956,957,960,962],{"class":80,"line":112},[78,958,959],{"class":95},"diagnostic_engine ",[78,961,118],{"class":91},[78,963,377],{"class":95},[78,965,966,969],{"class":80,"line":124},[78,967,968],{"class":127},"    \"postgresql+asyncpg:\u002F\u002Fadmin:secret@mydb.rds.amazonaws.com\u002Forders\"",[78,970,131],{"class":95},[78,972,973,975,977,979],{"class":80,"line":134},[78,974,138],{"class":137},[78,976,118],{"class":91},[78,978,690],{"class":143},[78,980,131],{"class":95},[78,982,983,985,987,990],{"class":80,"line":153},[78,984,156],{"class":137},[78,986,118],{"class":91},[78,988,989],{"class":143},"0",[78,991,131],{"class":95},[78,993,994],{"class":80,"line":166},[78,995,182],{"class":95},[78,997,998,1001,1003,1006,1008,1010],{"class":80,"line":179},[78,999,1000],{"class":95},"DiagnosticSession ",[78,1002,118],{"class":91},[78,1004,1005],{"class":95}," async_sessionmaker(diagnostic_engine, ",[78,1007,489],{"class":137},[78,1009,118],{"class":91},[78,1011,1012],{"class":95},"AsyncSession)\n",[78,1014,1015],{"class":80,"line":297},[78,1016,109],{"emptyLinePlaceholder":108},[78,1018,1019],{"class":80,"line":317},[78,1020,109],{"emptyLinePlaceholder":108},[78,1022,1023,1026,1029,1033,1036,1039],{"class":80,"line":343},[78,1024,1025],{"class":91},"async",[78,1027,1028],{"class":91}," def",[78,1030,1032],{"class":1031},"sScJk"," check_connection_budget",[78,1034,1035],{"class":95},"() -> ",[78,1037,1038],{"class":143},"None",[78,1040,1041],{"class":95},":\n",[78,1043,1044],{"class":80,"line":365},[78,1045,1046],{"class":127},"    \"\"\"Print current active connections grouped by application name.\"\"\"\n",[78,1048,1049,1052,1055,1058,1061],{"class":80,"line":370},[78,1050,1051],{"class":91},"    async",[78,1053,1054],{"class":91}," with",[78,1056,1057],{"class":95}," DiagnosticSession() ",[78,1059,1060],{"class":91},"as",[78,1062,1063],{"class":95}," session:\n",[78,1065,1066,1069,1071,1074],{"class":80,"line":380},[78,1067,1068],{"class":95},"        result ",[78,1070,118],{"class":91},[78,1072,1073],{"class":91}," await",[78,1075,1076],{"class":95}," session.execute(\n",[78,1078,1079],{"class":80,"line":388},[78,1080,1081],{"class":95},"            text(\n",[78,1083,1084],{"class":80,"line":398},[78,1085,1086],{"class":127},"                \"\"\"\n",[78,1088,1089],{"class":80,"line":408},[78,1090,1091],{"class":127},"                SELECT application_name,\n",[78,1093,1094],{"class":80,"line":421},[78,1095,1096],{"class":127},"                       state,\n",[78,1098,1099],{"class":80,"line":438},[78,1100,1101],{"class":127},"                       count(*) AS conn_count\n",[78,1103,1104],{"class":80,"line":450},[78,1105,1106],{"class":127},"                FROM   pg_stat_activity\n",[78,1108,1109],{"class":80,"line":462},[78,1110,1111],{"class":127},"                WHERE  datname = current_database()\n",[78,1113,1114],{"class":80,"line":467},[78,1115,1116],{"class":127},"                GROUP  BY application_name, state\n",[78,1118,1119],{"class":80,"line":472},[78,1120,1121],{"class":127},"                ORDER  BY conn_count DESC;\n",[78,1123,1124],{"class":80,"line":483},[78,1125,1086],{"class":127},[78,1127,1128],{"class":80,"line":505},[78,1129,1130],{"class":95},"            )\n",[78,1132,1133],{"class":80,"line":885},[78,1134,1135],{"class":95},"        )\n",[78,1137,1139,1142,1145,1148],{"class":80,"line":1138},28,[78,1140,1141],{"class":91},"        for",[78,1143,1144],{"class":95}," row ",[78,1146,1147],{"class":91},"in",[78,1149,1150],{"class":95}," result:\n",[78,1152,1154,1157,1159,1162,1165,1168,1171,1174,1177,1180,1182,1185,1188,1190,1193,1195,1198,1200,1202],{"class":80,"line":1153},29,[78,1155,1156],{"class":143},"            print",[78,1158,687],{"class":95},[78,1160,1161],{"class":91},"f",[78,1163,1164],{"class":127},"\"",[78,1166,1167],{"class":143},"{",[78,1169,1170],{"class":95},"row.application_name",[78,1172,1173],{"class":91},"!r:40s",[78,1175,1176],{"class":143},"}",[78,1178,1179],{"class":127},"  state=",[78,1181,1167],{"class":143},[78,1183,1184],{"class":95},"row.state",[78,1186,1187],{"class":91},"!r:15s",[78,1189,1176],{"class":143},[78,1191,1192],{"class":127},"  count=",[78,1194,1167],{"class":143},[78,1196,1197],{"class":95},"row.conn_count",[78,1199,1176],{"class":143},[78,1201,1164],{"class":127},[78,1203,182],{"class":95},[14,1205,1206,1207,1210,1211,1213,1214,1216,1217,1220],{},"If ",[18,1208,1209],{},"conn_count"," for your application name exceeds ",[18,1212,58],{}," per instance, either ",[18,1215,61],{}," connections are being actively used (acceptable under traffic spikes) or connections are leaking. Compare against ",[18,1218,1219],{},"pool.checkedout()"," from the engine introspection API to distinguish the two cases.",[520,1222,1224],{"id":1223},"aurora-vs-rds-connection-limit-differences","Aurora vs RDS: connection limit differences",[14,1226,1227,1228,1230,1231,1234,1235,1238,1239,35],{},"Aurora clusters present a subtlety: each Aurora instance (writer or reader) has its own ",[18,1229,46],{},", derived from its own instance class. The writer and each reader are separate endpoints with separate connection limits. If you route writes to ",[18,1232,1233],{},"cluster.cluster-xyz.rds.amazonaws.com"," and reads to ",[18,1236,1237],{},"cluster.cluster-ro-xyz.rds.amazonaws.com",", each engine's pool budget is calculated independently against the respective instance's ",[18,1240,46],{},[14,1242,1243,1244,1246,1247,1249],{},"Aurora Serverless v2 auto-scales ACUs (Aurora Capacity Units), which means ",[18,1245,46],{}," is not fixed. The minimum capacity's connection limit applies when the Aurora instance is cold; at maximum capacity, it scales proportionally. For Aurora Serverless v2, use a lower ",[18,1248,58],{}," (5–15) and rely on RDS Proxy for connection multiplexing to avoid exhausting the cold-start connection limit during scale-up events.",[37,1251,1253],{"id":1252},"resolving-warnings-errors-common-mistakes","Resolving Warnings, Errors & Common Mistakes",[1255,1256,1257,1273],"table",{},[1258,1259,1260],"thead",{},[1261,1262,1263,1267,1270],"tr",{},[1264,1265,1266],"th",{},"Error \u002F Warning",[1264,1268,1269],{},"Root Cause",[1264,1271,1272],{},"Production Fix",[1274,1275,1276,1300,1327,1352,1376,1396,1418],"tbody",{},[1261,1277,1278,1284,1294],{},[1279,1280,1281],"td",{},[18,1282,1283],{},"FATAL: remaining connection slots are reserved for non-replication superuser connections",[1279,1285,1286,1289,1290,1293],{},[18,1287,1288],{},"(pool_size + max_overflow) × instance_count"," exceeds ",[18,1291,1292],{},"max_connections - superuser_reserved_connections",". The superuser reserve (default 3) is the last line of defence.",[1279,1295,1296,1297,1299],{},"Recalculate budget with the formula above. Check if autoscaling added instances without reducing per-instance pool sizes. Lower ",[18,1298,58],{}," or add an RDS Proxy.",[1261,1301,1302,1307,1317],{},[1279,1303,1304],{},[18,1305,1306],{},"sqlalchemy.exc.TimeoutError: QueuePool limit of size X overflow Y reached, connection timed out, timeout 30",[1279,1308,1309,1310,1313,1314,1316],{},"All ",[18,1311,1312],{},"pool_size + max_overflow"," connections are checked out and ",[18,1315,536],{}," elapsed before one became available.",[1279,1318,1319,1320,1323,1324,1326],{},"First, confirm the database actually has available connections (",[18,1321,1322],{},"SHOW max_connections; SELECT count(*) FROM pg_stat_activity;","). If yes, increase ",[18,1325,58],{}," or optimize long-running transactions. If no, scale the RDS instance.",[1261,1328,1329,1334,1345],{},[1279,1330,1331],{},[18,1332,1333],{},"asyncpg.exceptions.TooManyConnectionsError: FATAL: too many connections for role \"app\"",[1279,1335,1336,1337,1340,1341,1344],{},"The database role has a ",[18,1338,1339],{},"CONNECTION LIMIT"," set (via ",[18,1342,1343],{},"ALTER ROLE app CONNECTION LIMIT 50",") that is lower than the total connections your instances attempt.",[1279,1346,1347,1348,1351],{},"Run ",[18,1349,1350],{},"ALTER ROLE app CONNECTION LIMIT -1;"," to remove the limit, or raise it to a value above your calculated worst-case total.",[1261,1353,1354,1359,1362],{},[1279,1355,1356],{},[18,1357,1358],{},"asyncpg.exceptions.ConnectionDoesNotExistError",[1279,1360,1361],{},"An idle connection in the pool was silently dropped by the RDS TCP idle timeout (default 8 h) or a security group change, then handed to a coroutine without validation.",[1279,1363,1364,1365,1368,1369,1372,1373,35],{},"Enable ",[18,1366,1367],{},"pool_pre_ping=True"," and set ",[18,1370,1371],{},"pool_recycle=1800",". For environments with aggressive idle timeouts (RDS Proxy default 1800 s), set ",[18,1374,1375],{},"pool_recycle=900",[1261,1377,1378,1383,1389],{},[1279,1379,1380],{},[18,1381,1382],{},"WARNING: there are already too many connections to the database",[1279,1384,1385,1386,1388],{},"PostgreSQL is at or near ",[18,1387,46],{},". Postgres logs this before refusing the next connection.",[1279,1390,1391,1392,1395],{},"Monitor ",[18,1393,1394],{},"SELECT count(*) FROM pg_stat_activity GROUP BY state;",". Reduce pool sizes or add a proxy.",[1261,1397,1398,1404,1407],{},[1279,1399,1400,1403],{},[18,1401,1402],{},"TimeoutError"," on first request after low-traffic period",[1279,1405,1406],{},"Pool connections were recycled while idle; all slots need fresh TCP handshakes simultaneously (cold burst).",[1279,1408,1409,1410,1413,1414,1417],{},"Pre-warm the pool during application startup: ",[18,1411,1412],{},"async with engine.connect() as conn: await conn.execute(text(\"SELECT 1\"))",". Repeat for ",[18,1415,1416],{},"pool_size \u002F\u002F 4"," connections.",[1261,1419,1420,1425,1432],{},[1279,1421,1422],{},[18,1423,1424],{},"sqlalchemy.exc.OperationalError: (asyncpg.exceptions.QueryCanceledError) ERROR: canceling statement due to statement timeout",[1279,1426,1427,1428,1431],{},"RDS Proxy or ",[18,1429,1430],{},"server_settings.statement_timeout"," terminated a long-running query, and the connection returned to the pool in a failed state.",[1279,1433,16,1434,1436,1437,1440,1441,1444],{},[18,1435,1367],{}," to validate connections on checkout. Ensure ",[18,1438,1439],{},"statement_timeout"," in ",[18,1442,1443],{},"connect_args"," matches or is lower than the proxy-level timeout.",[37,1446,1448],{"id":1447},"advanced-pool-sizing-optimization","Advanced Pool Sizing Optimization",[520,1450,1452,1453,1455],{"id":1451},"adapting-pool_size-per-worker-type-in-a-celery-deployment","Adapting ",[18,1454,58],{}," per worker type in a Celery deployment",[14,1457,1458,1459,1462],{},"Applications that run both an async API server and Celery workers against the same RDS instance must account for Celery worker connections in the total budget. Celery workers typically use synchronous drivers (",[18,1460,1461],{},"psycopg2","), which means each Celery worker thread holds one connection for the duration of a task.",[69,1464,1466],{"className":71,"code":1465,"language":73,"meta":74,"style":74},"import os\nfrom sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession\n\n# Shared budget constants (same RDS instance)\nRDS_MAX_CONNECTIONS = int(os.environ[\"RDS_MAX_CONNECTIONS\"])   # e.g. 683\nCELERY_WORKER_COUNT = int(os.environ.get(\"CELERY_WORKERS\", \"8\"))\nCELERY_CONCURRENCY  = int(os.environ.get(\"CELERY_CONCURRENCY\", \"4\"))  # threads per worker\nADMIN_RESERVE       = 15\n\ncelery_connections = CELERY_WORKER_COUNT * CELERY_CONCURRENCY   # 8 × 4 = 32\napi_budget         = RDS_MAX_CONNECTIONS - ADMIN_RESERVE - celery_connections  # 683-15-32 = 636\napi_instance_count = int(os.environ.get(\"API_INSTANCE_COUNT\", \"4\"))\nper_api_instance   = api_budget \u002F\u002F api_instance_count           # 636 \u002F\u002F 4 = 159\npool_size          = int(per_api_instance * 0.7)                # 111\nmax_overflow       = int(per_api_instance * 0.3)                # 47\n\napi_engine = create_async_engine(\n    os.environ[\"DATABASE_URL\"],\n    pool_size=pool_size,\n    max_overflow=max_overflow,\n    pool_timeout=30.0,\n    pool_recycle=1800,\n    pool_pre_ping=True,\n    echo=False,\n)\n\nApiSession = async_sessionmaker(api_engine, class_=AsyncSession, expire_on_commit=False)\n",[18,1467,1468,1474,1484,1488,1493,1511,1532,1557,1566,1570,1589,1610,1630,1651,1673,1693,1697,1706,1714,1722,1730,1740,1750,1760,1770,1774,1778],{"__ignoreMap":74},[78,1469,1470,1472],{"class":80,"line":81},[78,1471,99],{"class":91},[78,1473,579],{"class":95},[78,1475,1476,1478,1480,1482],{"class":80,"line":88},[78,1477,92],{"class":91},[78,1479,199],{"class":95},[78,1481,99],{"class":91},[78,1483,204],{"class":95},[78,1485,1486],{"class":80,"line":105},[78,1487,109],{"emptyLinePlaceholder":108},[78,1489,1490],{"class":80,"line":112},[78,1491,1492],{"class":84},"# Shared budget constants (same RDS instance)\n",[78,1494,1495,1497,1499,1501,1503,1505,1508],{"class":80,"line":124},[78,1496,218],{"class":143},[78,1498,221],{"class":91},[78,1500,325],{"class":143},[78,1502,604],{"class":95},[78,1504,607],{"class":127},[78,1506,1507],{"class":95},"])   ",[78,1509,1510],{"class":84},"# e.g. 683\n",[78,1512,1513,1516,1518,1520,1522,1525,1527,1530],{"class":80,"line":134},[78,1514,1515],{"class":143},"CELERY_WORKER_COUNT",[78,1517,221],{"class":91},[78,1519,325],{"class":143},[78,1521,645],{"class":95},[78,1523,1524],{"class":127},"\"CELERY_WORKERS\"",[78,1526,651],{"class":95},[78,1528,1529],{"class":127},"\"8\"",[78,1531,657],{"class":95},[78,1533,1534,1537,1539,1541,1543,1546,1548,1551,1554],{"class":80,"line":153},[78,1535,1536],{"class":143},"CELERY_CONCURRENCY",[78,1538,620],{"class":91},[78,1540,325],{"class":143},[78,1542,645],{"class":95},[78,1544,1545],{"class":127},"\"CELERY_CONCURRENCY\"",[78,1547,651],{"class":95},[78,1549,1550],{"class":127},"\"4\"",[78,1552,1553],{"class":95},"))  ",[78,1555,1556],{"class":84},"# threads per worker\n",[78,1558,1559,1561,1563],{"class":80,"line":166},[78,1560,245],{"class":143},[78,1562,640],{"class":91},[78,1564,1565],{"class":143}," 15\n",[78,1567,1568],{"class":80,"line":179},[78,1569,109],{"emptyLinePlaceholder":108},[78,1571,1572,1575,1577,1580,1583,1586],{"class":80,"line":297},[78,1573,1574],{"class":95},"celery_connections ",[78,1576,118],{"class":91},[78,1578,1579],{"class":143}," CELERY_WORKER_COUNT",[78,1581,1582],{"class":91}," *",[78,1584,1585],{"class":143}," CELERY_CONCURRENCY",[78,1587,1588],{"class":84},"   # 8 × 4 = 32\n",[78,1590,1591,1594,1596,1598,1600,1602,1604,1607],{"class":80,"line":317},[78,1592,1593],{"class":95},"api_budget         ",[78,1595,118],{"class":91},[78,1597,280],{"class":143},[78,1599,283],{"class":91},[78,1601,291],{"class":143},[78,1603,283],{"class":91},[78,1605,1606],{"class":95}," celery_connections  ",[78,1608,1609],{"class":84},"# 683-15-32 = 636\n",[78,1611,1612,1615,1617,1619,1621,1624,1626,1628],{"class":80,"line":343},[78,1613,1614],{"class":95},"api_instance_count ",[78,1616,118],{"class":91},[78,1618,325],{"class":143},[78,1620,645],{"class":95},[78,1622,1623],{"class":127},"\"API_INSTANCE_COUNT\"",[78,1625,651],{"class":95},[78,1627,1550],{"class":127},[78,1629,657],{"class":95},[78,1631,1632,1635,1637,1640,1642,1645,1648],{"class":80,"line":365},[78,1633,1634],{"class":95},"per_api_instance   ",[78,1636,118],{"class":91},[78,1638,1639],{"class":95}," api_budget ",[78,1641,308],{"class":91},[78,1643,1644],{"class":95}," api_instance_count           ",[78,1646,1647],{"class":84},"# 636",[78,1649,1650],{"class":84}," \u002F\u002F 4 = 159\n",[78,1652,1653,1656,1658,1660,1663,1665,1667,1670],{"class":80,"line":370},[78,1654,1655],{"class":95},"pool_size          ",[78,1657,118],{"class":91},[78,1659,325],{"class":143},[78,1661,1662],{"class":95},"(per_api_instance ",[78,1664,331],{"class":91},[78,1666,334],{"class":143},[78,1668,1669],{"class":95},")                ",[78,1671,1672],{"class":84},"# 111\n",[78,1674,1675,1678,1680,1682,1684,1686,1688,1690],{"class":80,"line":380},[78,1676,1677],{"class":95},"max_overflow       ",[78,1679,118],{"class":91},[78,1681,325],{"class":143},[78,1683,1662],{"class":95},[78,1685,331],{"class":91},[78,1687,357],{"class":143},[78,1689,1669],{"class":95},[78,1691,1692],{"class":84},"# 47\n",[78,1694,1695],{"class":80,"line":388},[78,1696,109],{"emptyLinePlaceholder":108},[78,1698,1699,1702,1704],{"class":80,"line":398},[78,1700,1701],{"class":95},"api_engine ",[78,1703,118],{"class":91},[78,1705,377],{"class":95},[78,1707,1708,1710,1712],{"class":80,"line":408},[78,1709,765],{"class":95},[78,1711,768],{"class":127},[78,1713,771],{"class":95},[78,1715,1716,1718,1720],{"class":80,"line":421},[78,1717,138],{"class":137},[78,1719,118],{"class":91},[78,1721,395],{"class":95},[78,1723,1724,1726,1728],{"class":80,"line":438},[78,1725,156],{"class":137},[78,1727,118],{"class":91},[78,1729,405],{"class":95},[78,1731,1732,1734,1736,1738],{"class":80,"line":450},[78,1733,411],{"class":137},[78,1735,118],{"class":91},[78,1737,416],{"class":143},[78,1739,131],{"class":95},[78,1741,1742,1744,1746,1748],{"class":80,"line":462},[78,1743,424],{"class":137},[78,1745,118],{"class":91},[78,1747,429],{"class":143},[78,1749,131],{"class":95},[78,1751,1752,1754,1756,1758],{"class":80,"line":467},[78,1753,169],{"class":137},[78,1755,118],{"class":91},[78,1757,445],{"class":143},[78,1759,131],{"class":95},[78,1761,1762,1764,1766,1768],{"class":80,"line":472},[78,1763,453],{"class":137},[78,1765,118],{"class":91},[78,1767,174],{"class":143},[78,1769,131],{"class":95},[78,1771,1772],{"class":80,"line":483},[78,1773,182],{"class":95},[78,1775,1776],{"class":80,"line":505},[78,1777,109],{"emptyLinePlaceholder":108},[78,1779,1780,1783,1785,1788,1790,1792,1794,1796,1798,1800],{"class":80,"line":885},[78,1781,1782],{"class":95},"ApiSession ",[78,1784,118],{"class":91},[78,1786,1787],{"class":95}," async_sessionmaker(api_engine, ",[78,1789,489],{"class":137},[78,1791,118],{"class":91},[78,1793,494],{"class":95},[78,1795,497],{"class":137},[78,1797,118],{"class":91},[78,1799,174],{"class":143},[78,1801,182],{"class":95},[14,1803,1804],{},"Treating Celery connections as a fixed reservation keeps the API pool safe from unexpected exhaustion when Celery workers spike.",[520,1806,1808],{"id":1807},"iam-token-authentication-and-pool_recycle-interaction","IAM token authentication and pool_recycle interaction",[14,1810,1811],{},"When using IAM database authentication with RDS, the IAM token used as the connection password is valid for 15 minutes. A connection created with an expired token continues to work — the token is only validated at connection time — but a recycled connection that initiates a new TCP handshake after the 15-minute window will fail authentication if the token is not refreshed.",[14,1813,1814,1815,1818],{},"The safest approach is to regenerate a fresh IAM token in a SQLAlchemy ",[18,1816,1817],{},"creator"," function, which is called each time the pool creates a new underlying connection:",[69,1820,1822],{"className":71,"code":1821,"language":73,"meta":74,"style":74},"import boto3\nfrom sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession\nfrom sqlalchemy.pool import NullPool\n\nrds_client = boto3.client(\"rds\", region_name=\"us-east-1\")\n\nRDS_HOST  = \"mydb.cluster-xyz.us-east-1.rds.amazonaws.com\"\nRDS_PORT  = 5432\nDB_USER   = \"app\"\nDB_NAME   = \"orders\"\n\n\ndef get_iam_token() -> str:\n    return rds_client.generate_db_auth_token(\n        DBHostname=RDS_HOST,\n        Port=RDS_PORT,\n        DBUsername=DB_USER,\n    )\n\n\n# asyncpg creator receives the sync connection-creation call\nimport asyncpg  # type: ignore\n\n\nasync def _create_asyncpg_conn() -> asyncpg.Connection:\n    token = get_iam_token()\n    return await asyncpg.connect(\n        host=RDS_HOST,\n        port=RDS_PORT,\n        user=DB_USER,\n        password=token,\n        database=DB_NAME,\n        ssl=\"require\",\n        statement_cache_size=0,\n    )\n\n\n# Use NullPool so each connection goes through the creator with a fresh token\niam_engine = create_async_engine(\n    f\"postgresql+asyncpg:\u002F\u002F{DB_USER}:placeholder@{RDS_HOST}\u002F{DB_NAME}\",\n    poolclass=NullPool,\n    echo=False,\n)\n",[18,1823,1824,1831,1841,1853,1857,1882,1886,1896,1906,1917,1927,1931,1935,1950,1958,1969,1980,1991,1996,2000,2004,2009,2019,2023,2027,2039,2049,2058,2069,2080,2092,2103,2115,2128,2140,2145,2150,2155,2161,2171,2199,2210,2221],{"__ignoreMap":74},[78,1825,1826,1828],{"class":80,"line":81},[78,1827,99],{"class":91},[78,1829,1830],{"class":95}," boto3\n",[78,1832,1833,1835,1837,1839],{"class":80,"line":88},[78,1834,92],{"class":91},[78,1836,199],{"class":95},[78,1838,99],{"class":91},[78,1840,204],{"class":95},[78,1842,1843,1845,1848,1850],{"class":80,"line":105},[78,1844,92],{"class":91},[78,1846,1847],{"class":95}," sqlalchemy.pool ",[78,1849,99],{"class":91},[78,1851,1852],{"class":95}," NullPool\n",[78,1854,1855],{"class":80,"line":112},[78,1856,109],{"emptyLinePlaceholder":108},[78,1858,1859,1862,1864,1867,1870,1872,1875,1877,1880],{"class":80,"line":124},[78,1860,1861],{"class":95},"rds_client ",[78,1863,118],{"class":91},[78,1865,1866],{"class":95}," boto3.client(",[78,1868,1869],{"class":127},"\"rds\"",[78,1871,651],{"class":95},[78,1873,1874],{"class":137},"region_name",[78,1876,118],{"class":91},[78,1878,1879],{"class":127},"\"us-east-1\"",[78,1881,182],{"class":95},[78,1883,1884],{"class":80,"line":134},[78,1885,109],{"emptyLinePlaceholder":108},[78,1887,1888,1891,1893],{"class":80,"line":153},[78,1889,1890],{"class":143},"RDS_HOST",[78,1892,620],{"class":91},[78,1894,1895],{"class":127}," \"mydb.cluster-xyz.us-east-1.rds.amazonaws.com\"\n",[78,1897,1898,1901,1903],{"class":80,"line":166},[78,1899,1900],{"class":143},"RDS_PORT",[78,1902,620],{"class":91},[78,1904,1905],{"class":143}," 5432\n",[78,1907,1908,1911,1914],{"class":80,"line":179},[78,1909,1910],{"class":143},"DB_USER",[78,1912,1913],{"class":91},"   =",[78,1915,1916],{"class":127}," \"app\"\n",[78,1918,1919,1922,1924],{"class":80,"line":297},[78,1920,1921],{"class":143},"DB_NAME",[78,1923,1913],{"class":91},[78,1925,1926],{"class":127}," \"orders\"\n",[78,1928,1929],{"class":80,"line":317},[78,1930,109],{"emptyLinePlaceholder":108},[78,1932,1933],{"class":80,"line":343},[78,1934,109],{"emptyLinePlaceholder":108},[78,1936,1937,1940,1943,1945,1948],{"class":80,"line":365},[78,1938,1939],{"class":91},"def",[78,1941,1942],{"class":1031}," get_iam_token",[78,1944,1035],{"class":95},[78,1946,1947],{"class":143},"str",[78,1949,1041],{"class":95},[78,1951,1952,1955],{"class":80,"line":370},[78,1953,1954],{"class":91},"    return",[78,1956,1957],{"class":95}," rds_client.generate_db_auth_token(\n",[78,1959,1960,1963,1965,1967],{"class":80,"line":380},[78,1961,1962],{"class":137},"        DBHostname",[78,1964,118],{"class":91},[78,1966,1890],{"class":143},[78,1968,131],{"class":95},[78,1970,1971,1974,1976,1978],{"class":80,"line":388},[78,1972,1973],{"class":137},"        Port",[78,1975,118],{"class":91},[78,1977,1900],{"class":143},[78,1979,131],{"class":95},[78,1981,1982,1985,1987,1989],{"class":80,"line":398},[78,1983,1984],{"class":137},"        DBUsername",[78,1986,118],{"class":91},[78,1988,1910],{"class":143},[78,1990,131],{"class":95},[78,1992,1993],{"class":80,"line":408},[78,1994,1995],{"class":95},"    )\n",[78,1997,1998],{"class":80,"line":421},[78,1999,109],{"emptyLinePlaceholder":108},[78,2001,2002],{"class":80,"line":438},[78,2003,109],{"emptyLinePlaceholder":108},[78,2005,2006],{"class":80,"line":450},[78,2007,2008],{"class":84},"# asyncpg creator receives the sync connection-creation call\n",[78,2010,2011,2013,2016],{"class":80,"line":462},[78,2012,99],{"class":91},[78,2014,2015],{"class":95}," asyncpg  ",[78,2017,2018],{"class":84},"# type: ignore\n",[78,2020,2021],{"class":80,"line":467},[78,2022,109],{"emptyLinePlaceholder":108},[78,2024,2025],{"class":80,"line":472},[78,2026,109],{"emptyLinePlaceholder":108},[78,2028,2029,2031,2033,2036],{"class":80,"line":483},[78,2030,1025],{"class":91},[78,2032,1028],{"class":91},[78,2034,2035],{"class":1031}," _create_asyncpg_conn",[78,2037,2038],{"class":95},"() -> asyncpg.Connection:\n",[78,2040,2041,2044,2046],{"class":80,"line":505},[78,2042,2043],{"class":95},"    token ",[78,2045,118],{"class":91},[78,2047,2048],{"class":95}," get_iam_token()\n",[78,2050,2051,2053,2055],{"class":80,"line":885},[78,2052,1954],{"class":91},[78,2054,1073],{"class":91},[78,2056,2057],{"class":95}," asyncpg.connect(\n",[78,2059,2060,2063,2065,2067],{"class":80,"line":1138},[78,2061,2062],{"class":137},"        host",[78,2064,118],{"class":91},[78,2066,1890],{"class":143},[78,2068,131],{"class":95},[78,2070,2071,2074,2076,2078],{"class":80,"line":1153},[78,2072,2073],{"class":137},"        port",[78,2075,118],{"class":91},[78,2077,1900],{"class":143},[78,2079,131],{"class":95},[78,2081,2083,2086,2088,2090],{"class":80,"line":2082},30,[78,2084,2085],{"class":137},"        user",[78,2087,118],{"class":91},[78,2089,1910],{"class":143},[78,2091,131],{"class":95},[78,2093,2095,2098,2100],{"class":80,"line":2094},31,[78,2096,2097],{"class":137},"        password",[78,2099,118],{"class":91},[78,2101,2102],{"class":95},"token,\n",[78,2104,2106,2109,2111,2113],{"class":80,"line":2105},32,[78,2107,2108],{"class":137},"        database",[78,2110,118],{"class":91},[78,2112,1921],{"class":143},[78,2114,131],{"class":95},[78,2116,2118,2121,2123,2126],{"class":80,"line":2117},33,[78,2119,2120],{"class":137},"        ssl",[78,2122,118],{"class":91},[78,2124,2125],{"class":127},"\"require\"",[78,2127,131],{"class":95},[78,2129,2131,2134,2136,2138],{"class":80,"line":2130},34,[78,2132,2133],{"class":137},"        statement_cache_size",[78,2135,118],{"class":91},[78,2137,989],{"class":143},[78,2139,131],{"class":95},[78,2141,2143],{"class":80,"line":2142},35,[78,2144,1995],{"class":95},[78,2146,2148],{"class":80,"line":2147},36,[78,2149,109],{"emptyLinePlaceholder":108},[78,2151,2153],{"class":80,"line":2152},37,[78,2154,109],{"emptyLinePlaceholder":108},[78,2156,2158],{"class":80,"line":2157},38,[78,2159,2160],{"class":84},"# Use NullPool so each connection goes through the creator with a fresh token\n",[78,2162,2164,2167,2169],{"class":80,"line":2163},39,[78,2165,2166],{"class":95},"iam_engine ",[78,2168,118],{"class":91},[78,2170,377],{"class":95},[78,2172,2174,2177,2180,2183,2186,2189,2192,2195,2197],{"class":80,"line":2173},40,[78,2175,2176],{"class":91},"    f",[78,2178,2179],{"class":127},"\"postgresql+asyncpg:\u002F\u002F",[78,2181,2182],{"class":143},"{DB_USER}",[78,2184,2185],{"class":127},":placeholder@",[78,2187,2188],{"class":143},"{RDS_HOST}",[78,2190,2191],{"class":127},"\u002F",[78,2193,2194],{"class":143},"{DB_NAME}",[78,2196,1164],{"class":127},[78,2198,131],{"class":95},[78,2200,2202,2205,2207],{"class":80,"line":2201},41,[78,2203,2204],{"class":137},"    poolclass",[78,2206,118],{"class":91},[78,2208,2209],{"class":95},"NullPool,\n",[78,2211,2213,2215,2217,2219],{"class":80,"line":2212},42,[78,2214,453],{"class":137},[78,2216,118],{"class":91},[78,2218,174],{"class":143},[78,2220,131],{"class":95},[78,2222,2224],{"class":80,"line":2223},43,[78,2225,182],{"class":95},[14,2227,2228,2229,2232,2233,2236,2237,2240,2241,2243],{},"For production IAM auth with a ",[18,2230,2231],{},"QueuePool",", set ",[18,2234,2235],{},"pool_recycle"," to ",[18,2238,2239],{},"800"," (well below the 900-second token validity window minus connection handshake time) and regenerate the token in the ",[18,2242,1817],{}," callback. This ensures every recycled connection picks up a fresh token automatically.",[37,2245,2247],{"id":2246},"frequently-asked-questions","Frequently Asked Questions",[14,2249,2250,2256,2257,2259,2260,2262],{},[65,2251,2252,2253,2255],{},"How do I find the exact ",[18,2254,46],{}," for my RDS instance class without connecting?","\nThe AWS RDS documentation publishes connection limits per instance class, but they can lag behind actual values after engine version upgrades. The reliable approach is to query ",[18,2258,50],{}," directly, or look it up in the RDS Parameter Group in the AWS Console under the ",[18,2261,46],{}," parameter — it shows the formula-derived value for your instance.",[14,2264,2265,2273,2274,2277],{},[65,2266,2267,2268,21,2270,2272],{},"Should I always use the 70\u002F30 split between ",[18,2269,58],{},[18,2271,61],{},"?","\nThe 70\u002F30 split is a safe default. For batch-heavy workloads that have long transaction bursts followed by idle periods, a 60\u002F40 split gives more burst headroom. For high-concurrency APIs with short-lived transactions, an 80\u002F20 split reduces the number of overflow connections that are discarded after use, improving connection reuse. Validate with load testing: measure p99 checkout latency and ",[18,2275,2276],{},"pool.overflow()"," under peak traffic.",[14,2279,2280,2289,2290,2292,2293,2296],{},[65,2281,2282,2283,2286,2287,2272],{},"Can I set ",[18,2284,2285],{},"pool_size=0"," and rely entirely on ",[18,2288,61],{},"\nNo. A pool with ",[18,2291,2285],{}," creates only overflow connections, all of which are discarded after use. Every checkout incurs a fresh TCP handshake and TLS negotiation — 10–100 ms on RDS. Under sustained load this causes severe latency degradation. Use ",[18,2294,2295],{},"NullPool"," explicitly if you want no pooling (e.g., behind RDS Proxy), which makes the intent clear.",[14,2298,2299,2305,2307],{},[65,2300,2301,2302,2304],{},"What is the right ",[18,2303,536],{}," for RDS?",[18,2306,416],{}," seconds is a reasonable default. Set it lower (10–15 s) if your API has strict SLA requirements and you'd rather fail fast and return an error than queue indefinitely. Set it higher (60 s) only for batch jobs where user impact is low and a brief queue during a traffic spike is acceptable.",[37,2309,2311],{"id":2310},"related","Related",[2313,2314,2315,2321,2332,2343],"ul",{},[2316,2317,2318,2320],"li",{},[31,2319,34],{"href":33}," — Full cloud pooling guide covering GCP Cloud SQL, Azure, PgBouncer, RDS Proxy, and Lambda patterns.",[2316,2322,2323,2327,2328,2331],{},[31,2324,2326],{"href":2325},"\u002Fasync-engines-dialects-and-connection-pooling\u002Fconfiguring-async-engines-and-connection-pools\u002F","Configuring Async Engines and Connection Pools"," — Baseline ",[18,2329,2330],{},"create_async_engine"," initialization and pool parameter reference.",[2316,2333,2334,2338,2339,2342],{},[31,2335,2337],{"href":2336},"\u002Fasync-engines-dialects-and-connection-pooling\u002Fhandling-connection-leaks-and-pool-exhaustion\u002F","Handling Connection Leaks and Pool Exhaustion"," — Diagnosing ",[18,2340,2341],{},"PoolTimeout"," and connection leak patterns in production.",[2316,2344,2345,2349],{},[31,2346,2348],{"href":2347},"\u002Fasync-engines-dialects-and-connection-pooling\u002Fchoosing-between-asyncpg-and-psycopg-async-drivers\u002Fusing-sqlalchemy-async-with-celery-task-workers\u002F","Using SQLAlchemy Async with Celery Task Workers"," — Integrating async engines alongside synchronous Celery workers sharing the same RDS instance.",[2351,2352,2353],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .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 .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);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":74,"searchDepth":88,"depth":88,"links":2355},[2356,2357,2363,2364,2369,2370],{"id":39,"depth":88,"text":40},{"id":517,"depth":88,"text":518,"children":2358},[2359,2360,2361,2362],{"id":522,"depth":105,"text":523},{"id":548,"depth":105,"text":549},{"id":915,"depth":105,"text":916},{"id":1223,"depth":105,"text":1224},{"id":1252,"depth":88,"text":1253},{"id":1447,"depth":88,"text":1448,"children":2365},[2366,2368],{"id":1451,"depth":105,"text":2367},"Adapting pool_size per worker type in a Celery deployment",{"id":1807,"depth":105,"text":1808},{"id":2246,"depth":88,"text":2247},{"id":2310,"depth":88,"text":2311},"Set pool_size = floor((rds_max_connections - reserved) \u002F instance_count * 0.7) and max_overflow = floor(pool_size \u002F 2), then verify that (pool_size + max_overflow) * instance_count never exceeds the usable connection budget — this is the core formula for safe RDS pool sizing, and the full derivation with cloud-specific context lives in Tuning Connection Pools for Cloud Databases.","md",{"date":2374},"2026-06-18","\u002Fasync-engines-dialects-and-connection-pooling\u002Ftuning-connection-pools-for-cloud-databases\u002Fsetting-pool-size-and-max-overflow-for-aws-rds",{"title":5,"description":2371},"async-engines-dialects-and-connection-pooling\u002Ftuning-connection-pools-for-cloud-databases\u002Fsetting-pool-size-and-max-overflow-for-aws-rds\u002Findex","4TWxZiSM6-whX19jLmtXR-neYAbC-FISQZbS-3IDYPc",1781810028984]