Connect to PostgreSQL
Tested with: PostgreSQL 17.6 on Databasezy · drivers listed per tab · zb CLI 0.1
- Open the instance in the portal, go to Connect, and copy the host and port. Credentials were shown once at creation; if you lost them, rotate them.
- Download the CA bundle from the same tab (or run
zb api GET /v1/orgs/{org}/ca.pem > databasezy-ca.pem). The gateway presents a publicly trusted certificate, but libpq-based drivers do not read the OS trust store, so pass the bundle explicitly. - Add your application’s egress IPs to Network → Allow-list. Connections from other addresses are refused at the gateway before authentication.
- Use one of the snippets below. Every one of them runs
sslmode=verify-fullor the driver’s equivalent: the chain is verified and the hostname must match.
PostgreSQL listens on port 5432 (PostgreSQL wire protocol). Versions: 18, 17, 16, 15. Replace the example host with the one on your instance's Connect tab; credentials are shown once at creation.
postgresql://app:<password>@pg-7f3k.us-east.databasezy.com:5432/app?sslmode=verify-full&sslrootcert=databasezy-ca.pemimport { readFileSync } from "node:fs";import { Pool } from "pg";
const host = "pg-7f3k.us-east.databasezy.com";export const pool = new Pool({ host, port: 5432, database: "app", user: "app", password: process.env.ZB_PASSWORD, ssl: { ca: readFileSync("databasezy-ca.pem", "utf8"), rejectUnauthorized: true, // verify chain servername: host, // verify hostname (verify-full) }, max: 10, // keep well under the size's max_connections idleTimeoutMillis: 30_000,});
const { rows } = await pool.query("select version()");console.log(rows[0]);Tested with: PostgreSQL 18 · node-postgres (pg) 8.13
import osfrom psycopg_pool import ConnectionPool
conninfo = ( "host=pg-7f3k.us-east.databasezy.com port=5432 dbname=app user=app " f"password={os.environ['ZB_PASSWORD']} " "sslmode=verify-full sslrootcert=databasezy-ca.pem")pool = ConnectionPool(conninfo, min_size=1, max_size=10)
with pool.connection() as conn: print(conn.execute("select version()").fetchone())Tested with: PostgreSQL 18 · psycopg 3.2 · psycopg_pool 3.2
package main
import ( "context" "fmt" "os"
"github.com/jackc/pgx/v5/pgxpool")
func main() { ctx := context.Background() dsn := fmt.Sprintf( "postgres://app:%s@pg-7f3k.us-east.databasezy.com:5432/app?sslmode=verify-full&sslrootcert=databasezy-ca.pem&pool_max_conns=10", os.Getenv("ZB_PASSWORD"), ) pool, err := pgxpool.New(ctx, dsn) if err != nil { panic(err) } defer pool.Close()
var v string if err := pool.QueryRow(ctx, "select version()").Scan(&v); err != nil { panic(err) } fmt.Println(v)}Tested with: PostgreSQL 18 · pgx v5.7
use sqlx::postgres::{PgConnectOptions, PgPoolOptions, PgSslMode};
#[tokio::main]async fn main() -> Result<(), sqlx::Error> { let opts = PgConnectOptions::new() .host("pg-7f3k.us-east.databasezy.com") .port(5432) .database("app") .username("app") .password(&std::env::var("ZB_PASSWORD").expect("ZB_PASSWORD")) .ssl_mode(PgSslMode::VerifyFull) .ssl_root_cert("databasezy-ca.pem");
let pool = PgPoolOptions::new().max_connections(10).connect_with(opts).await?; let (v,): (String,) = sqlx::query_as("select version()").fetch_one(&pool).await?; println!("{v}"); Ok(())}Tested with: PostgreSQL 18 · sqlx 0.8 (runtime-tokio, tls-rustls)
import com.zaxxer.hikari.HikariConfig;import com.zaxxer.hikari.HikariDataSource;
public final class Db { public static HikariDataSource open() { var cfg = new HikariConfig(); cfg.setJdbcUrl("jdbc:postgresql://pg-7f3k.us-east.databasezy.com:5432/app" + "?sslmode=verify-full&sslrootcert=databasezy-ca.pem"); cfg.setUsername("app"); cfg.setPassword(System.getenv("ZB_PASSWORD")); cfg.setMaximumPoolSize(10); return new HikariDataSource(cfg); }}Tested with: PostgreSQL 18 · PostgreSQL JDBC 42.7 · HikariCP 6.2
using Npgsql;
var cs = new NpgsqlConnectionStringBuilder{ Host = "pg-7f3k.us-east.databasezy.com", Port = 5432, Database = "app", Username = "app", Password = Environment.GetEnvironmentVariable("ZB_PASSWORD"), SslMode = SslMode.VerifyFull, RootCertificate = "databasezy-ca.pem", MaxPoolSize = 10,};await using var dataSource = NpgsqlDataSource.Create(cs);await using var cmd = dataSource.CreateCommand("select version()");Console.WriteLine(await cmd.ExecuteScalarAsync());Tested with: PostgreSQL 18 · Npgsql 9.0
<?php$dsn = "pgsql:host=pg-7f3k.us-east.databasezy.com;port=5432;dbname=app;" . "sslmode=verify-full;sslrootcert=databasezy-ca.pem";$pdo = new PDO($dsn, "app", getenv("ZB_PASSWORD"), [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_PERSISTENT => true, // reuse connections across requests]);echo $pdo->query("select version()")->fetchColumn();Tested with: PostgreSQL 18 · PHP 8.3 · PDO pgsql
require "pg"
conn = PG.connect( host: "pg-7f3k.us-east.databasezy.com", port: 5432, dbname: "app", user: "app", password: ENV.fetch("ZB_PASSWORD"), sslmode: "verify-full", sslrootcert: "databasezy-ca.pem")puts conn.exec("select version()").firstTested with: PostgreSQL 18 · pg 1.5 · Ruby 3.3
# Connection URI (copy from Instance → Connect in the portal)export DATABASE_URL='postgresql://app:<password>@pg-7f3k.us-east.databasezy.com:5432/app?sslmode=verify-full&sslrootcert=databasezy-ca.pem'
psql "$DATABASE_URL"# or with zb (spawns psql with TLS flags and a one-time credential)zb connect pg-7f3kTested with: PostgreSQL 18 · psql 17
- The minimum is TLS 1.2; TLS 1.3 is negotiated by every driver above. Plaintext is never offered; a client that refuses TLS is disconnected with a clear error.
sslmode=requireencrypts but does not verify the server. Useverify-fullin production; it is the default in all snippets here.- Certificates are rotated automatically every 60 days. Pin the CA (intermediate), never the leaf; rotation dates are published twelve months ahead on the mTLS and pinning page.
Pooling
Section titled “Pooling”- Each size has a hard
max_connections(see the size catalogue). Keep the sum of your application pools under it and leave headroom for migrations andpsql. - Serverless and edge runtimes open a connection per invocation. Enable the built-in transaction-mode pooler on
Connect → Pooler and use the pooled endpoint; see Connection pooling for the trade-offs
(no session state, no
LISTEN, prepared statements per transaction). - Idle connections do not keep a free-tier instance awake; it sleeps after 15 minutes without traffic and wakes on the next connection (the first query after wake takes a few seconds).
IP allow-list
Section titled “IP allow-list”The allow-list is enforced by the gateway for every plan, including Free. Add CIDRs, not single addresses, for
platforms with rotating egress IPs, or use the platform’s static-egress feature (documented per platform under
Platforms). 0.0.0.0/0 is allowed but flagged in the portal and in the audit log.