PostgreSQL Wire Protocol
ParticleDB implements the PostgreSQL wire protocol (v3), making it compatible with every PostgreSQL client, driver, and ORM. This is the primary interface for all SQL operations.
Connection
Section titled “Connection”Connection string format
Section titled “Connection string format”postgresql://[user[:password]@]host[:port][/database][?params]Examples:
# Default (no auth)postgresql://localhost:5432/main
# With authenticationpostgresql://admin:secret@localhost:5432/main
# With SSLpostgresql://admin:secret@localhost:5432/main?sslmode=require
# Unix socket (lowest latency)postgresql:///main?host=/tmp# TCP connectionpsql -h localhost -p 5432 -d main
# Unix socketpsql -h /tmp -d main
# With user/passwordpsql -h localhost -p 5432 -U admin -d mainDefault configuration
Section titled “Default configuration”| Setting | Default |
|---|---|
| Listen address | 0.0.0.0:5432 |
| Unix socket | Disabled (enable with --pg-unix-socket) |
| Auth method | trust (no password) |
| Max connections | 100 |
| Idle timeout | 300 seconds |
Supported PostgreSQL Features
Section titled “Supported PostgreSQL Features”Query protocol
Section titled “Query protocol”| Feature | Status |
|---|---|
| Simple query | Supported |
| Extended query (Parse / Bind / Execute) | Supported |
| Prepared statements (named and unnamed) | Supported |
Parameter binding ($1, $2, …) | Supported |
Portal suspension (max_rows) | Supported |
| COPY FROM STDIN (tab-separated) | Supported |
| LISTEN / NOTIFY | Not yet supported |
Data formats
Section titled “Data formats”| Format | Status | Notes |
|---|---|---|
| Text format | Supported | Default for most clients |
| Binary format | Supported | 2-4x faster for numeric types |
Transactions
Section titled “Transactions”| Feature | Status |
|---|---|
BEGIN / COMMIT / ROLLBACK | Supported |
SAVEPOINT / ROLLBACK TO | Supported |
| Transaction isolation (SSI) | Supported |
SET TRANSACTION | Supported |
| PostgreSQL Type | ParticleDB Mapping |
|---|---|
BIGINT / INT8 | 64-bit signed integer |
INTEGER / INT4 | 32-bit signed integer |
DOUBLE PRECISION / FLOAT8 | 64-bit IEEE float |
REAL / FLOAT4 | 32-bit IEEE float |
VARCHAR / TEXT | UTF-8 string |
BOOLEAN | Boolean |
TIMESTAMP | Microsecond-precision timestamp |
DATE | Calendar date |
JSON / JSONB | JSON document |
BYTEA | Binary data |
VECTOR(n) | n-dimensional float vector |
Pipeline Mode
Section titled “Pipeline Mode”Pipeline mode sends multiple queries in a single network round-trip, dramatically reducing latency for high-throughput workloads. ParticleDB processes pipelined queries under a single lock acquisition for maximum efficiency.
How it works
Section titled “How it works”In pipeline mode, the client sends multiple Bind + Execute message pairs before waiting for results. ParticleDB buffers the responses and flushes them all on Sync.
Client ParticleDB |--- Parse ------------------>| |--- Bind (val=1) ----------->| |--- Execute ----------------->| |--- Bind (val=2) ----------->| |--- Execute ----------------->| |--- Bind (val=3) ----------->| |--- Execute ----------------->| |--- Sync ------------------->| |<-- ParseComplete -----------| |<-- BindComplete ------------| |<-- DataRow (result 1) -----| |<-- CommandComplete ---------| |<-- BindComplete ------------| |<-- DataRow (result 2) -----| |<-- CommandComplete ---------| |<-- BindComplete ------------| |<-- DataRow (result 3) -----| |<-- CommandComplete ---------| |<-- ReadyForQuery ----------|Pipeline depth
Section titled “Pipeline depth”Higher pipeline depth amortizes per-query overhead:
| Pipeline Depth | Throughput (single connection) |
|---|---|
| 1 (no pipeline) | ~107K ops/sec |
| 32 | ~2.4M ops/sec |
| 256 | ~5.7M ops/sec |
| 1024 | ~6.4M ops/sec |
Client support
Section titled “Client support”PQenterPipelineMode(conn);PQsendQueryParams(conn, "SELECT * FROM t WHERE id=$1", 1, NULL, vals1, NULL, NULL, 0);PQsendQueryParams(conn, "SELECT * FROM t WHERE id=$1", 1, NULL, vals2, NULL, NULL, 0);PQpipelineSync(conn);// Read results...PQexitPipelineMode(conn);// node-postgres does not have native pipeline mode,// but you can batch with Promise.all over a single connection:const [r1, r2, r3] = await Promise.all([ client.query("SELECT * FROM products WHERE id = $1", [1]), client.query("SELECT * FROM products WHERE id = $1", [2]), client.query("SELECT * FROM products WHERE id = $1", [3]),]);batch := &pgx.Batch{}batch.Queue("SELECT * FROM products WHERE id = $1", 1)batch.Queue("SELECT * FROM products WHERE id = $1", 2)batch.Queue("SELECT * FROM products WHERE id = $1", 3)
br := conn.SendBatch(ctx, batch)defer br.Close()
for i := 0; i < 3; i++ { rows, _ := br.Query() // process rows... rows.Close()}Binary Format
Section titled “Binary Format”Binary format eliminates text parsing overhead for numeric types. An INT8 is transferred as 8 raw bytes instead of its ASCII representation.
Enabling binary format
Section titled “Enabling binary format”Most drivers enable binary format through a connection option or per-query flag:
# asyncpg uses binary format by defaultimport asyncpgconn = await asyncpg.connect("postgresql://localhost:5432/main")
# psycopg2: use server-side cursors with binarycur = conn.cursor("my_cursor")cur.execute("SELECT id, price FROM products")// pgx uses binary format by default for known typesconn, _ := pgx.Connect(ctx, "postgresql://localhost:5432/main")SSL / TLS
Section titled “SSL / TLS”Enable TLS on the server:
particledb start \ --tls-cert /path/to/server.crt \ --tls-key /path/to/server.keyClient connection with TLS:
psql "postgresql://localhost:5432/main?sslmode=require"See TLS / Security for full certificate configuration.
Authentication
Section titled “Authentication”ParticleDB supports three authentication methods for the PG wire protocol:
| Method | Flag | Description |
|---|---|---|
trust | --auth-method trust | No password required (default) |
password | --auth-method password | Cleartext password (use with TLS) |
md5 | --auth-method md5 | MD5-hashed password |
# Start with password authparticledb start --auth-method password --pg-password mysecret
# Connect with passwordpsql "postgresql://admin:mysecret@localhost:5432/main"Compatible Clients
Section titled “Compatible Clients”ParticleDB has been tested with the following PostgreSQL clients:
| Client | Language | Status |
|---|---|---|
psql | CLI | Tested |
psycopg2 | Python | Tested |
asyncpg | Python | Tested |
pg (node-postgres) | TypeScript/JS | Tested |
pgx | Go | Tested |
tokio-postgres | Rust | Tested |
| PostgreSQL JDBC | Java | Tested |
Npgsql | C# / .NET | Tested |
libpq | C | Tested |
| DBeaver | GUI | Tested |
| DataGrip | GUI | Tested |
| pgAdmin | GUI | Tested |
COPY FROM STDIN
Section titled “COPY FROM STDIN”ParticleDB supports the PostgreSQL COPY ... FROM STDIN protocol for bulk data loading
over the wire. Data is sent in tab-separated format with one row per line.
# Load data from a TSV file via psqlpsql -h localhost -d main -c "COPY products FROM STDIN" < products.tsv
# Or interactively in psqlpsql -h localhost -d mainmain=# COPY products (id, name, price) FROM STDIN;1 Widget 9.992 Gadget 19.99\.The server reads CopyData messages from the client until it receives a CopyDone
message, then bulk-inserts the parsed rows. This is significantly faster than individual
INSERT statements for large data loads.
Wire Protocol Diagnostics
Section titled “Wire Protocol Diagnostics”Two environment variables enable detailed protocol-level debugging:
PDB_WIRE_TRACE
Section titled “PDB_WIRE_TRACE”Set PDB_WIRE_TRACE=1 to log every PG wire message (Parse, Bind, Execute, Describe,
Sync, Close) with per-message timing. Useful for understanding query sequencing and
identifying round-trip overhead.
PDB_WIRE_TRACE=1 particledb start --pg-addr 0.0.0.0:5432Example output:
[WIRE] Parse stmt="" query="SELECT $1::int8"[WIRE] Bind stmt="" portal="" params=1[WIRE] Execute portal="" max_rows=0[WIRE] Sync[WIRE] total=42usPDB_WIRE_DUMP
Section titled “PDB_WIRE_DUMP”Set PDB_WIRE_DUMP=1 for byte-level message framing output. This dumps the raw wire
bytes (message type tag, length, payload) and is intended for debugging protocol
interoperability issues with specific drivers.
PDB_WIRE_DUMP=1 particledb startBinary Format Compatibility
Section titled “Binary Format Compatibility”ParticleDB correctly parses the format code field in Bind messages, which specifies whether parameter values are in text (0) or binary (1) format. A fix was applied to handle the JDBC driver’s convention of sending a single format code that applies to all parameters (as opposed to one format code per parameter). This ensures correct binary parameter decoding for PostgreSQL JDBC and other drivers that use the compact format.
ClientCompat Mode
Section titled “ClientCompat Mode”Some PostgreSQL clients (notably older JDBC versions and certain ORMs) send protocol messages that deviate slightly from the v3 specification. ParticleDB includes a ClientCompat detection layer that identifies the client during the startup handshake and adjusts behavior accordingly:
- JDBC: Accepts single-format-code Bind messages; returns
INT4OIDs forParameterDescriptionwhen the client advertises JDBC in theapplication_namestartup parameter. - psql: Sends
RowDescriptionfields with the display format the client expects (text by default, even when the server prefers binary). - Default: Strict v3 compliance for all other clients.
ClientCompat is automatic and requires no configuration.
Unix Socket
Section titled “Unix Socket”For the lowest possible latency when client and server are on the same machine, use a Unix domain socket:
# Start with Unix socketparticledb start --pg-unix-socket /tmp/.s.PGSQL.5432
# Connect via Unix socketpsql -h /tmp -p 5432 -d mainThe default socket path is /tmp/.s.particledb.5432.
Next Steps
Section titled “Next Steps”- SDKs — Language-specific connection guides
- TLS / Security — Encryption and authentication
- ORM Compatibility — Tested ORMs and frameworks
- Configuration — All server flags