Neon (Serverless PostgreSQL)

raw JSON →
platform verified Tue May 12 auth: no python install: verified quickstart: stale

Neon is a serverless PostgreSQL platform (acquired by Databricks May 2025 for ~$1B). Not a Python package — connect using standard PostgreSQL drivers (psycopg2, psycopg, asyncpg, SQLAlchemy). Two connection string types: pooled (-pooler in hostname, via PgBouncer) and direct. Pooled is now the default in Neon Console. Critical: always include sslmode=require. asyncpg with pooled connections requires statement_cache_size=0.

pip install psycopg2-binary
error ERROR: The endpoint ID is not specified.
cause This error occurs when an older PostgreSQL client library (libpq) or application does not support the Server Name Indication (SNI) mechanism in TLS, which Neon uses to route incoming connections based on compute IDs.
fix
Upgrade your PostgreSQL client library to version 14 or higher (which supports SNI), or explicitly pass the endpoint ID as a parameter in the connection string, for example, '&options=endpoint%3D[endpoint_id]' or by specifying it in the password field as 'endpoint=[endpoint_id];[password]'.
error FATAL: password authentication failed for user "your_user"
cause This is a general PostgreSQL authentication error, which in Neon often arises from incorrect database credentials (username, password, or database name) or by not including `sslmode=require` in the connection string, as Neon requires all connections to use SSL/TLS encryption.
fix
Verify that the username, password, and database name in your connection string are correct. Ensure that sslmode=require (or sslmode=verify-full for stronger security) is explicitly included in your connection string.
error SSL connection has been closed unexpectedly
cause This error, often seen as `SSL SYSCALL error: EOF detected`, typically occurs when an application tries to reuse a database connection after the Neon compute instance has scaled down to zero due to inactivity, causing the connection to become stale.
fix
For SQLAlchemy, upgrade to version 2.0.33 or later, set pool_recycle to a value less than or equal to your Neon compute's scale-to-zero setting, and enable pool_pre_ping=True to ensure connections are alive before use. Alternatively, avoid pooled connections for long-lived applications by using NullPool with external pooling.
error asyncpg.exceptions.InvalidSQLStatementNameError: unnamed prepared statement does not exist HINT: NOTE: pgbouncer with pool_mode set to "transaction" or "statement" does not support prepared statements properly.
cause This error occurs when using `asyncpg` with Neon's pooled connections (which use PgBouncer in transaction mode), because PgBouncer in this mode does not properly support PostgreSQL's prepared statements that `asyncpg` might attempt to use.
fix
Disable asyncpg's prepared statement cache by setting statement_cache_size=0 when creating the asyncpg connection pool. If using SQLAlchemy with asyncpg, also ensure prepared_statement_name_func is set to generate unique names for statements.
breaking sslmode=require is mandatory for Neon connections. Omitting it causes SSL errors or connection refusal. Neon enforces TLS.
fix Always append ?sslmode=require to connection strings. Neon Console copies include it automatically.
breaking asyncpg with Neon pooler (PgBouncer transaction mode) raises 'prepared statement asyncpg_stmt_X does not exist'. Breaks under any concurrent load.
fix await asyncpg.create_pool(dsn, statement_cache_size=0)
breaking Schema migrations (Alembic, Django migrate, Prisma Migrate) must use the DIRECT connection string, not the pooled one. PgBouncer transaction mode breaks migration session state.
fix Set DATABASE_URL_UNPOOLED (no -pooler in hostname) for migration commands. Use DATABASE_URL (pooler) for app traffic.
gotcha Neon computes scale to zero after inactivity. First connection after idle period has 300-500ms cold start latency. Using the pooler (PgBouncer) mitigates this — PgBouncer maintains warm connections.
fix Use pooled connection string for web apps. Consider Neon's 'always-on' setting for latency-sensitive workloads.
gotcha Pooled connection strings are now the default in Neon Console (since Jan 2025). If you copied a connection string before Jan 2025 it may be a direct connection without -pooler.
fix Check your connection string hostname. Pooled: ep-xxx-pooler.region.aws.neon.tech. Direct: ep-xxx.region.aws.neon.tech.
gotcha SQLAlchemy with asyncpg on Neon pooler requires statement_cache_size=0 in connect_args: create_async_engine(url, connect_args={'statement_cache_size': 0})
fix engine = create_async_engine(DATABASE_URL, connect_args={'statement_cache_size': 0})
breaking The 'ModuleNotFoundError: No module named 'dotenv'' indicates that the 'python-dotenv' package, required for loading environment variables from a .env file, is not installed in the execution environment.
fix Ensure 'python-dotenv' is listed in your project's dependencies (e.g., requirements.txt or pyproject.toml) and is properly installed. You can install it manually using `pip install python-dotenv`.
breaking The `dotenv` package is required by the application but was not found. This typically means the package was not included in the project's dependencies or failed to install.
fix Ensure `python-dotenv` is listed in your project's `requirements.txt` or equivalent dependency management file, and that dependencies are installed correctly (e.g., `pip install python-dotenv`).
pip install psycopg
pip install asyncpg
python os / libc variant status wheel install import disk
3.10 alpine (musl) asyncpg - - - -
3.10 alpine (musl) psycopg - - - -
3.10 alpine (musl) psycopg2-binary - - 0.04s 77.4M
3.10 slim (glibc) asyncpg - - - -
3.10 slim (glibc) psycopg - - - -
3.10 slim (glibc) psycopg2-binary - - 0.04s 152M
3.11 alpine (musl) asyncpg - - - -
3.11 alpine (musl) psycopg - - - -
3.11 alpine (musl) psycopg2-binary - - 0.07s 83.7M
3.11 slim (glibc) asyncpg - - - -
3.11 slim (glibc) psycopg - - - -
3.11 slim (glibc) psycopg2-binary - - 0.07s 158M
3.12 alpine (musl) asyncpg - - - -
3.12 alpine (musl) psycopg - - - -
3.12 alpine (musl) psycopg2-binary - - 0.05s 74.2M
3.12 slim (glibc) asyncpg - - - -
3.12 slim (glibc) psycopg - - - -
3.12 slim (glibc) psycopg2-binary - - 0.05s 149M
3.13 alpine (musl) asyncpg - - - -
3.13 alpine (musl) psycopg - - - -
3.13 alpine (musl) psycopg2-binary - - 0.05s 70.7M
3.13 slim (glibc) asyncpg - - - -
3.13 slim (glibc) psycopg - - - -
3.13 slim (glibc) psycopg2-binary - - 0.05s 147M
3.9 alpine (musl) asyncpg - - - -
3.9 alpine (musl) psycopg - - - -
3.9 alpine (musl) psycopg2-binary - - 0.04s 76.6M
3.9 slim (glibc) asyncpg - - - -
3.9 slim (glibc) psycopg - - - -
3.9 slim (glibc) psycopg2-binary - - 0.04s 151M

Minimal Neon PostgreSQL connection with psycopg2.

# pip install psycopg2-binary python-dotenv
import psycopg2
from dotenv import load_dotenv
import os

load_dotenv()

# Use pooled URL from Neon Console (includes -pooler in hostname)
conn = psycopg2.connect(os.environ['DATABASE_URL'])
# DATABASE_URL=postgresql://user:pass@ep-xxx-pooler.region.aws.neon.tech/neondb?sslmode=require

cur = conn.cursor()
cur.execute('SELECT version()')
print(cur.fetchone())

cur.execute(
    'SELECT * FROM users WHERE id = %s',
    (1,)
)
rows = cur.fetchall()

cur.close()
conn.close()