Connection strings
Format, TLS, role and password rules for Kisenon endpoints.
Every Kisenon endpoint exposes a standard postgresql:// URI:
postgresql://<role>:<pwd>@<endpoint_id>.<region>.kisenon.com:5432/<database>?sslmode=requireComponents
| Field | Meaning |
|---|---|
<role> | A Postgres role created on the branch. The endpoint card shows the auto-created app role; you can create more via SQL. |
<pwd> | The role's password. Surfaced once at creation; rotate via SQL. |
<endpoint_id> | Stable per endpoint, e.g. 5e0c7d1a-8b2f-4e36-9a41-c7d2e8f03b15. SNI-routed. |
<region> | Your project's region slug — usc1 today (US Central, GCP). Derived, not hardcoded; see Regions. |
kisenon.com | The data-plane apex. Routes via TLS SNI to your endpoint. |
5432 | Standard Postgres port. |
<database> | Default main; create more with CREATE DATABASE. |
?sslmode=require | TLS is mandatory. require encrypts, but most drivers don't check the server certificate under it — see Verifying the server certificate. |
TLS
Endpoints terminate TLS with a Let's Encrypt certificate for
*.<region>.kisenon.com, so no custom CA is needed.
The connection string Kisenon hands out — the console's Connection
string format, keon connection-string, and the API — uses
sslmode=require. The connection is encrypted, but under require most
drivers do not check the server's certificate. It stays the default
because it is the one value every driver accepts.
Verifying the server certificate
To have your driver check the certificate chain and the hostname, use the parameters for your driver. The console's per-driver formats already do.
| Driver | Parameters |
|---|---|
psql and other libpq tools (libpq 16+) | sslmode=verify-full&sslrootcert=system |
| Python: psycopg 3, psycopg2, SQLAlchemy, Django | sslmode=verify-full&sslrootcert=system (see binary wheels below) |
Node.js: pg, Drizzle, postgres.js | sslmode=verify-full |
| Prisma 6 and 7 | sslmode=verify-full&sslaccept=strict |
| Go: pgx v5.7.0+, lib/pq v1.12.0+ | sslmode=verify-full&sslrootcert=system |
| Go: older pgx or lib/pq | sslmode=verify-full |
| Java: JDBC, Spring | sslmode=verify-full&sslfactory=org.postgresql.ssl.DefaultJavaSSLFactory |
| .NET: Npgsql, EF Core | SSL Mode=VerifyFull |
@kisenon/serverless | Nothing to add: it connects over HTTPS/WebSocket and ignores sslmode. |
What catches people out:
- libpq older than 16 does not understand
sslrootcert=system. Usesslmode=requirethere as a deliberate fallback: encrypted, not verified. - Never give a Node.js driver
sslrootcert=system.pg(and Prisma 7, which uses it) tries to read a file namedsystemand fails; postgres.js sends it to the server, which rejects the connection. - Python binary wheels (
psycopg[binary],psycopg2-binary) bundle their own OpenSSL, whose system trust store is empty, sosslrootcert=systemfails withcertificate verify failed. Point it at your OS bundle withSSL_CERT_FILE— on Debian/Ubuntu,SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt. The path differs on other systems. - Windows has no PEM trust store, so
sslrootcert=systemfails withcertificate verify failedin every libpq-based client —psql, psycopg, the Rubypggem. Pointsslrootcertat a CA bundle file instead. From Python, use certifi:pip install certifi, thensslrootcert=certifi.where()(this works on every OS, which is why the console's Python formats use it). Forpsqlor Rails, download the Mozilla bundle fromhttps://curl.se/ca/cacert.pemand pass its path:sslrootcert=C:\certs\cacert.pem. - Prisma 6 does not check the certificate unless
sslaccept=strictis set, whateversslmodesays. - postgres.js does not check the certificate under
sslmode=require. - JDBC with plain
sslmode=verify-fulllooks for~/.postgresql/root.crt;sslfactory=org.postgresql.ssl.DefaultJavaSSLFactorymakes it use the JVM trust store instead.
How the proxy routes to your endpoint
The data-plane proxy decides which endpoint a connection belongs to from two signals, in order:
- The
neon.endpoint_idstartup option, if the client sends one. - The TLS SNI hostname (
<endpoint_id>.<region>.kisenon.com) as a fallback.
The username field is not consulted for routing — pick any role your branch defines. Console-generated connection strings carry the endpoint in the hostname, so they route via SNI automatically and you don't need to set anything extra.
Pass neon.endpoint_id explicitly only when your client can't present
the endpoint in SNI — for example a TLS stack that won't send a Server
Name extension, or a tunnel that rewrites the host. Most Postgres
drivers send SNI by default, so this is rarely needed.
Connection pooling
Pooling is GA and on by default — every endpoint has a pooled host alongside its direct one (since 2026-07-18).
The pooled host is <endpoint_id>-pooler.<region>.kisenon.com — the same
endpoint, with -pooler inserted into the host label — on port 5432
with sslmode=require:
postgresql://<role>:<pwd>@<endpoint_id>-pooler.<region>.kisenon.com:5432/<database>?sslmode=requireThe console Connect panel and the API response both hand you a
connection_uri_pooled alongside the direct connection_uri.
The pooler runs in transaction pooling mode (a PgBouncer sidecar per compute). That's ideal for many short-lived connections — serverless functions, edge runtimes, agents — where each transaction can borrow a server connection and return it immediately.
Use the direct (unpooled :5432) connection instead when you need:
LISTEN/NOTIFY.- Session-level advisory locks.
- Session
SET/ GUCs that must outlive a single transaction. - Server-side prepared statements.
The direct connection_uri is always available and is never removed, so
these keep working exactly as before. A client-side pool (PgBouncer or
your driver's built-in pool) in front of the direct connection also
remains valid.
Opt an endpoint out of pooling with the pooler_enabled: false field at
create time or via PATCH /v1/endpoints/{endpointId}. The default is
true.
Multiple endpoints
You can spawn multiple endpoints on the same branch. They share storage but have independent connection limits and caches. Use them to isolate:
- App vs analytics traffic.
- Read replicas (any endpoint on a branch is essentially a read replica if you don't write to it).
- Per-environment endpoints on dev branches.