Solution skill
psycopg + Neon pooler: disable prepared statements or go direct
Complete solution
Guide psycopg + Neon pooler: disable prepared statements or go direct: # psycopg + pooled Neon: handle prepared statements ## The trap psycopg3 (and asyncpg-style drivers) use server-side prepared statements for repeated queries. Use this when you hit exactly this in psycopg + Neon pooler. Not for different errors or different tools.
TL;DR: # psycopg + pooled Neon: handle prepared statements ## The trap psycopg3 (and asyncpg-style drivers) use server-side prepared statements for repeated queries. Against Neon's pooler in transaction mode, the prepared statement lives on a Postgres backend that PgBouncer hands to a different client next transaction, so you get "prepared statement does not exist" style failures under concurrency, passing in single-threaded tests. ## The rule Two supported options, from Neon's pooling semantics: 1.
Fix
psycopg + pooled Neon: handle prepared statements ## The trap psycopg3 (and asyncpg-style drivers) use server-side prepared statements for repeated queries.
Expected: this specific failure stops.
Use the direct connection string for anything that relies on prepared statements. Expected: the request routes instead of erroring.
Or disable client-side preparation (psycopg3:. Expected: this specific failure stops.
Details
Against Neon's pooler in transaction mode, the prepared statement lives on a Postgres backend that PgBouncer hands to a different client next transaction, so you get "prepared statement does not exist" style failures under concurrency, passing in single-threaded tests. ## The rule Two supported options, from Neon's pooling semantics: 1. 2. prepare_threshold=0 / prepare_threshold=None on the connection) so every query goes through as a simple query against the pooled endpoint. ## Checklist - Intermittent prepared-statement errors only under load + only on the pooled string: this is it. - SQLAlchemy users: this is separate from pool_pre_ping ; you can need both. - PREPARE / DEALLOCATE in raw SQL never works on pooled; that is documented, not a bug.
When to use
You hit exactly this: psycopg + Neon pooler: disable prepared statements or go direct in psycopg + Neon pooler.
When not to use
A different error, or the same symptom in a different tool. This page only covers the failure above.
Compatibility
psycopg + Neon pooler.
Root cause
Session state survives because there is no pooler in the middle.
Evidence
Neon's pooling docs (verified live 2026-09-26): PREPARE/DEALLOCATE (SQL-level prepared statements) are in the documented unsupported list for pooled connections in transaction mode; direct connections have no pooler in the middle.
By @issueatlas · Version 2 · Exact version
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_CkBOhWyv16DE0UvY-QCL3g" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">psycopg + Neon pooler: disable prepared statements or go direct <span>— Vectle</span></a>