Connect string reference

A single connect string configures the QuestDB native client. The same string format drives QWP (QuestDB Wire Protocol) ingress, QWP egress, multi-host failover, and the store-and-forward substrate. All language implementations share one option vocabulary, so the same connect string can configure both ingress and egress in any client. Where an implementation deviates, the affected key section and client page call it out.

One ws:: / wss:: connect string serves both the ingress sender and the egress query client. Each direction reads the keys relevant to it and ignores keys meant only for the other direction, so the same string configures both without edits. The Applies to: tag on each section below marks which direction a key affects.

For legacy InfluxDB Line Protocol (ILP) transports (http, https, tcp, tcps), see the ILP overview.

On this page:

Syntax

A connect string has the form:

schema::key1=value1;key2=value2;

The schema selects the wire protocol and transport. The remaining key=value pairs configure it. The trailing semicolon is optional but recommended.

For example:

ws::addr=localhost:9000;username=admin;password=secret;

This selects the QWP WebSocket transport, connects to localhost:9000, and provides basic-auth credentials.

For the list of supported schemas, see Protocols and transports.

Grammar

  • Schema — alphanumeric ASCII characters and underscore. Terminated by ::.
  • Key — alphanumeric ASCII characters and underscore. Terminated by =. Keys are case-sensitive; the canonical form is lowercase snake_case.
  • Value — any character except control characters (U+0000–U+001F, U+007F–U+009F). Terminated by ;.
  • Escaping — to include a literal ; in a value, double it (;;).

Example with an escaped semicolon in a password (the actual password value is p;ssw;rd):

ws::addr=localhost:9000;username=admin;password=p;;ssw;;rd;

Loading a connect string

The Java client accepts a connect string in three ways:

  • From a string literal:

    Sender sender = Sender.fromConfig("ws::addr=localhost:9000;");
  • From an environment variable (reads QDB_CLIENT_CONF):

    Sender sender = Sender.fromEnv();
  • From the builder, which accepts the same option keys programmatically:

    Sender sender = Sender.builder(Transport.WS)
    .address("localhost:9000")
    .build();

Other language clients expose equivalent entry points; see each client library page for the per-language syntax.

Common patterns

Canonical shapes for typical deployments. Extend each with auth, failover, or store-and-forward options from the sections below.

Local development (no auth, no TLS)

ws::addr=localhost:9000;

Production with basic auth (TLS)

wss::addr=questdb.example.com:443;username=admin;password=secret;

Production with a custom trust store

wss::addr=questdb.example.com:443;username=admin;password=secret;tls_roots=/etc/questdb/ca-roots;tls_roots_password=changeit;

Ingest with store-and-forward across multiple nodes

wss::addr=node-a:9000,node-b:9000;sf_dir=/var/lib/myapp/qdb-sf;sender_id=ingest-1;

Query (egress) preferring a replica in your zone

wss::addr=node-a:443,node-b:443;target=replica;zone=eu-west-1a;

Tolerate a slow or restarting server at startup

ws::addr=node-a:9000;reconnect_max_duration_millis=120000;

The 2-minute reconnect budget covers both the first connect and any subsequent reconnect: setting any explicit reconnect_* key implicitly turns on initial_connect_retry. See Ingress reconnect.

Recipes

Goal-to-keys mapping. For complete connect-string templates, see Common patterns. For per-key details (type, default, caveats), follow the section links from the Key index.

GoalDirectionRequired keysOptional / related
Minimal connect stringbothaddr
Enable TLSbothaddr with wss schematls_verify, tls_roots, tls_roots_password
Basic-auth credentialsbothusername, passwordauth_timeout_ms
Bearer-token credentialsbothtokenauth_timeout_ms
Multi-host failoverbothaddr=h1,h2,…target, zone, reconnect_* (ingress), failover_* (egress)
Query only the primary (freshest data)egresstarget=primary
Query only replicas (offload primary)egresstarget=replica
Zone-aware routing with DR last-resortegresszone=<id>target
Tune ingest batchingingressClients with auto-flush: auto_flush_rows, auto_flush_interval, auto_flush_bytes
Disable auto-flush (manual flush() only)ingressauto_flush=off
Memory-buffered ingest (no disk durability)ingress(omit sf_dir)init_buf_size, max_buf_size
Durable store-and-forward ingestingresssf_dirsender_id, sf_max_segment_bytes, sf_max_total_bytes, sf_append_deadline_millis
Run multiple senders sharing one sf_diringresssf_dir, sender_idunique sender_id per sender
Orphan recovery for crashed sendersingressdrain_orphans=onmax_background_drainers
End-to-end durable acknowledgementingressrequest_durable_ack=ondurable_ack_keepalive_interval_millis
Tune ingress reconnect backoffingressreconnect_initial_backoff_millis, reconnect_max_backoff_millis, reconnect_max_duration_millis (any of these also implies initial_connect_retry=on)
Force fail-fast on initial connectingressinitial_connect_retry=offoverrides the implicit promotion from any explicit reconnect_* key
Retry initial connect in backgroundingressinitial_connect_retry=asyncreconnect_*
Fast close() without drainingressclose_flush_timeout_millis=0
Disable per-query egress failoveregressfailover=off
Tune per-query egress failoveregressfailover_max_attempts, failover_backoff_initial_ms, failover_backoff_max_ms, failover_max_duration_ms
Configure async error inboxbotherror_inbox_capacity

Protocols and transports

Applies to: ingress and egress.

The schema prefix selects the QWP transport.

SchemaTransportDefault portNotes
wsWebSocket9000QWP over plain WebSocket. Use for development or trusted networks.
wssWebSocket + TLS9000QWP over TLS-secured WebSocket. Recommended for production.
udpUDP9007Fire-and-forget metrics ingest, single table per datagram.

The client applies the default port when addr omits :port. Note that wss does not default to 443: both ws and wss use 9000 unless overridden.

QWP negotiates its protocol version during the WebSocket upgrade — clients do not need to configure it.

Authentication

Applies to: ingress and egress.

QWP runs over WebSocket and uses HTTP-style credentials sent on the WebSocket upgrade request.

  • username — username for HTTP basic authentication. user is an accepted alias.
  • password — password for HTTP basic authentication. pass is an accepted alias.
  • token — bearer token sent as Authorization: Bearer <token>. Mutually exclusive with username / password. Token auth avoids the per-request overhead of basic auth and is the recommended path for Enterprise deployments.
  • auth_timeout_ms — per-host upper bound on the upgrade response read. Does not cover TLS handshake or post-upgrade frame reads, which use OS or hard-coded defaults. Default: 15000 (15 s).
  • connect_timeout — integer milliseconds, must be > 0. Applies to ingress and egress. Bounds the TCP connect phase for each endpoint, so a black-holed host in a multi-host addr no longer stalls the endpoint walk until the OS connect timeout. Unset by default.

Mutual TLS (mTLS). Not supported. The client validates the server's certificate against a trust store but cannot present a client certificate; the TLS handshake is server-authenticated only. tls_roots / tls_roots_password configure server-cert trust, not client identity. Use token=<token> or username= / password= for client authentication.

TLS

Applies to: ingress and egress.

Selecting the wss schema enables TLS.

  • tls_verify — controls server certificate verification. Options: on, unsafe_off. Default: on. unsafe_off disables verification; use only for testing — bypassing verification makes the connection vulnerable to MITM attacks. Mutually exclusive with tls_roots — see below.

  • tls_roots — path to a file of trusted root certificates, used instead of the system trust store. If omitted, the client uses the system default trust store. The accepted on-disk formats are client-specific:

    ClientFormats accepted at tls_roots
    JavaPEM (default, no password), JKS, PKCS#12
    Rust, C, C++, PythonPEM (default), JKS, PKCS#12
    .NETPKCS#12 / PFX
    Gonone — OS trust store only, both keys rejected at parse time
  • tls_roots_password — password for the tls_roots file. Required only for a JKS or PKCS#12 trust store; PEM needs no password. Setting it without tls_roots is an error.

tls_roots and tls_verify=unsafe_off cannot be combined

Supplying both is rejected at connect time:

tls_roots cannot be combined with tls_verify=unsafe_off; remove tls_verify to
use custom roots, or remove tls_roots to disable certificate validation

The two express opposite intents — one pins a private CA, the other switches verification off entirely. Pick one. For a self-signed certificate in a test environment, tls_verify=unsafe_off alone is enough; to actually validate against your own CA, supply tls_roots and leave tls_verify at its default.

PEM is the passwordless default path on Java, Rust, C, C++ and Python, so a private CA needs no keytool import:

wss::addr=db.example.com:9000;tls_roots=/etc/ssl/ca.pem;

Existing JKS and PKCS#12 trust stores keep working through tls_roots_password, and PKCS#12 now also loads on Java 8.

Client support varies

The Go client verifies against the operating-system trust store only and rejects both keys at parse time; to trust a private CA there, install it in the host trust store. On Rust, C, C++ and Python, tls_roots_password switches the file to a Java keystore and is QWP/WebSocket only: other transports keep PEM as the sole format. Check the relevant client library page for specifics.

QuestDB does not support mutual TLS (client certificates) — the server does not negotiate client certificates regardless of client. See Authentication for the supported credential paths.

See also the server-side TLS configuration.

Auto-flushing

Applies to: ingress.

The client buffers rows in memory and flushes them to the server in batches. For clients that implement auto-flushing, these keys control when the client sends the buffer without an explicit flush() call. The three triggers below act independently: whichever threshold trips first sends the batch.

  • auto_flush — global enable. Options: on, off. Default where supported: on. When off, the application must call flush() explicitly to send buffered rows.
  • auto_flush_rows — flush when the buffered row count reaches this threshold. Set to off to disable. Default where supported: 1000.
  • auto_flush_interval — flush when this many milliseconds have elapsed since the first buffered row. The client evaluates the interval on the next at() / flush() call, not on a wall-clock timer. Set to off to disable. Default where supported: 100 (100 ms).
  • auto_flush_bytes — flush when the encode buffer reaches this byte size. Set to off to disable. Accepts size suffixes. The default differs by client: Java ships it disabled (0), .NET defaults to 8m (8 MiB), and Rust, C and C++ reject the key outright. A Java application that assumes an 8 MiB byte trigger is active will size batches expecting a flush that never fires. When set to a positive value, the client clamps the effective threshold down to 90% of the server- advertised X-QWP-Max-Batch-Size at handshake (one-way: the client keeps a configured value already below the advertised cap). The 10% margin absorbs encoding overhead such as schema and dict-delta bytes. Setting off opts out of byte-based auto-flush entirely — the handshake clamp does not re-enable it, and the application takes responsibility for not producing oversized batches. Older servers that do not advertise the header leave the configured value untouched.
Rust support

The Rust client currently does not implement auto-flushing. It accepts auto_flush=off for compatibility and rejects auto_flush=on, auto_flush_rows, auto_flush_interval, and auto_flush_bytes. Rust applications must call flush() explicitly; see the Rust client page.

Buffer sizing

Applies to: ingress (encode buffer).

These keys control the in-memory row buffer that the client uses before flushing.

  • init_buf_size — initial buffer size in bytes. Default: 65536 (64 KiB). Accepts size suffixes.
  • max_buf_size — maximum buffer size; the buffer grows up to this cap. Default: 104857600 (100 MiB). Accepts size suffixes.
  • max_name_len — maximum allowed length of a table or column name in bytes. Default: 127.
  • max_datagram_size — UDP only. Maximum datagram size; defaults to a value below typical Ethernet MTU.

Size suffixes

Size-typed values (init_buf_size, max_buf_size, sf_max_segment_bytes, sf_max_total_bytes) accept JVM-style unit suffixes. Suffixes are case-insensitive and 1024-based, matching -Xmx conventions:

SuffixMeaningExample
(none)bytes65536
k or kbKiB (× 1024)64k
m or mbMiB (× 1024²)4m, 4mb
g or gbGiB (× 1024³)1g, 10gb
t or tbTiB (× 1024⁴)1t

Multi-host failover

Applies to: ingress and egress. The Role filter and zone preference sub-section is egress only.

QuestDB Enterprise

Multi-host failover requires QuestDB Enterprise. OSS is single-node — there is no secondary server to fail over to.

The connect string accepts multiple host:port pairs in addr. The parser accepts two syntaxes and accumulates entries across both:

wss::addr=node-a:9000,node-b:9000,node-c:9000;
ws::addr=node-a:9000;addr=node-b:9000;addr=node-c:9000;

The parser rejects empty entries (,,, or leading / trailing commas), and also rejects a duplicate host:port — listing the same endpoint twice fails at connect time with duplicate addr entry: <host:port>. This catches the common case of templating an address list that collapses to the same node, which would otherwise silently halve your effective failover breadth.

The I/O loop rotates through the endpoints on every reconnect attempt within a single outage budget. When the server rejects the connection because the current host is in the wrong role, the client treats it as failover input and immediately tries the next endpoint without waiting for backoff.

Role filter and zone preference

Both target and zone apply to egress only. QuestDB is currently a single-primary cluster: ingress automatically follows the primary across the host list and adapts when the primary moves to another node. Ingress silently accepts these keys and ignores them.

  • target — server-role filter applied per endpoint after the upgrade reads SERVER_INFO. Options:

    • any (default) — no preference; route to any healthy endpoint.
    • primary — route only to the writer. Use when queries must see the most recent data; replicas are eventually consistent and may lag the primary.
    • replica — route only to replicas. Use for historical or analytical queries to avoid contending with the ingest traffic the primary is handling.

    The client skips endpoints whose role does not match the filter.

  • zone — client zone identifier (opaque, case-insensitive — e.g. eu-west-1a, dc-amsterdam). When set, egress prefers endpoints whose server-advertised zone_id matches the client's. Mismatched-zone endpoints — typically a remote DR replica — drop to a lower priority tier; the client routes to them only as a last resort, when every same-zone endpoint is unhealthy. With target=primary, zone preference collapses: the writer is followed regardless of zone.

Client failover documents the full behavioural model — host picker policy, host-health states, error classification, and backoff schedule. The High Availability section covers server-side HA separately.

Related: Reconnect and failover, Store-and-forward.

Enable DEDUP on tables ingested through failover

On unplanned failover — when the primary dies before issuing a durable ACK — the client replays unacknowledged frames against the new primary. Without DEDUP on the target table, those replays can produce duplicate rows. Tables ingested through a multi-host failover connect string must declare DEDUP UPSERT KEYS(...) covering row identity. See Delivery semantics for the full at-least-once / exactly-once model.

Store-and-forward

Applies to: ingress.

Store-and-forward (SF) is an opt-in durability substrate available on QWP / WebSocket. The client persists outgoing frames to disk before sending; the server's cumulative ACK trims acknowledged segments. If the connection drops or the client process restarts, the I/O thread silently reconnects and replays whatever is still on disk.

To enable SF mode, set sf_dir. Without it, the client runs a memory-only equivalent — same architecture, no durability across restarts.

Storage

  • sf_dir — parent directory under which the slot lives. The slot path is <sf_dir>/<sender_id>/. Required for SF mode; omit for memory-only mode. Path handling:

    • Taken verbatim. Absolute paths recommended for production; relative paths resolve against the process working directory.
    • The client does not expand shell-style syntax such as ~.
    • The client creates the leaf directory if it is missing, but the parent must already exist — it does not create paths recursively.
  • sender_id — slot identity. The slot lives at <sf_dir>/<sender_id>/, used verbatim as the directory name. Allowed characters: letters, digits, _, -. No path separators, no ., no spaces. Two senders sharing the same sender_id collide on the slot lock — the second one fails fast. Default: default. For pooled senders, sender_id is the slot base rather than a literal directory: the pool mints one directory per slot, and the un-suffixed path applies only to non-pooled senders. The minted name is client-specific:

    ClientMinted slot directory
    Java (QuestDB facade)<sf_dir>/<sender_id>-<index>/
    Rust, C, C++ (QuestDb / questdb::pool / questdb_db)<sf_dir>/<sender_id>-ingest-<index>/

    The minted names belong to that pool's namespace, so pools sharing one sf_dir need distinct bases; the slot-in-use error covers both cases (another process or pool holds the slot).

  • sf_durability — disk durability mode. memory (the default) and periodic both ship. periodic requires sf_dir and checkpoints published frames in the background at sf_sync_interval_millis. flush and append are reserved: they parse but are rejected at build().

    Reach for periodic when you must survive host loss. memory mode is process-crash durable but not host-crash durable, because the page cache is lost on power failure.

    The .NET client is the exception: it accepts only memory and rejects anything else at parse time.

  • sf_sync_interval_millis — cadence at which sf_durability=periodic checkpoints published frames to stable storage. Default: 5000. Requires sf_durability=periodic; rejected otherwise. The configured interval is a floor, since scheduler and storage latency add to it.

  • sf_max_segment_bytes — per-segment rotation threshold. Must be ≥ the largest single flushed frame. Default: 4 MiB (4m). Accepts size suffixes.

  • sf_max_total_bytes — hard cap on per-slot storage. When the slot reaches the cap, append() blocks until ACKs trim space (see sf_append_deadline_millis). Defaults: 10 GiB (10g) in SF mode, 128 MiB (128m) in memory mode. Accepts size suffixes.

Sender restart and replay

SF persists outgoing frames and the durable-ack watermark to disk under <sf_dir>/<sender_id>/.

Sender creation triggers recovery. When the application instantiates a new sender — Sender.fromConfig(...), Sender.fromEnv(), or the builder — the client analyses the on-disk state under sf_dir before returning control. There is no background daemon; replay is part of the Sender lifecycle.

To resume from the previous session's buffer after a restart — clean exit, SIGKILL, host crash, or reboot — instantiate a new sender with the same sf_dir and sender_id:

  1. The new sender acquires the slot's POSIX flock (LockFileEx on Windows). If the previous process is still alive and holds the lock, the new sender fails fast with sf slot already in use. The kernel releases the lock on process exit, even after SIGKILL, so a crashed sender does not leave the slot stuck.
  2. Recovery reads the persisted ack watermark and replays every on-disk segment past it against the server. Replay runs on the I/O thread in parallel with the application's new append() calls — it does not block the application.

If sf_dir is a relative path, ensure the process resolves it the same way after restart (typically: use an absolute path).

For a different sender to pick up an abandoned slot — the original is never coming back — see Orphan recovery below.

At-least-once delivery. Replay can re-send frames the server already accepted but did not durable-acknowledge before the previous sender died. To prevent duplicate rows in the target table, declare DEDUP UPSERT KEYS(...) covering row identity. See Delivery semantics for the full model and recipe.

Backpressure

  • sf_append_deadline_millis — maximum time append() waits for trim to free space when the slot hits the cap. If the deadline fires, the call throws. Default: 30000 (30 s).

Orphan recovery

When drain_orphans=on, the new sender scans <sf_dir>/* at startup for sibling slots that are unlocked and contain unacked data. The scan runs as part of Sender creation (alongside the same-slot recovery above). The sender locks each orphan slot, drains it on its own dedicated connection, and releases it — multiple orphans drain in parallel, up to max_background_drainers concurrent drains.

  • drain_orphanson enables the orphan drainer pool. Default: off.
  • max_background_drainers — maximum concurrent drainers. Default: 4.

For delivery semantics, architecture, and tradeoffs (at-least-once guarantees, DEDUP requirements, segment-granular trim), see Store-and-forward concepts.

Reconnect and failover

Applies to: ingress and egress (separate key families).

QWP / WebSocket has two distinct recovery loops, each with its own knob family. The ingress cursor-engine reconnect loop runs continuously for the lifetime of the sender. The egress per-Execute() failover loop runs once per query.

Ingress reconnect

These keys control the cursor-engine reconnect loop used by QWP ingest. SF mode and memory-only mode share the same loop. A running sender retries a transport outage indefinitely with capped exponential backoff — there is no wall-clock give-up: the whole point of the buffering architecture is that a producer survives an arbitrarily long outage.

  • reconnect_initial_backoff_millis — initial wait between reconnect attempts. Backoff grows exponentially up to reconnect_max_backoff_millis. Default: 100. Setting this enables initial_connect_retry=on implicitly; see below.

  • reconnect_max_backoff_millis — cap on per-attempt backoff. Default: 5000 (5 s). Setting this enables initial_connect_retry=on implicitly; see below.

  • reconnect_max_duration_millis — time budget for the blocking sync initial connect (initial_connect_retry=on): once exceeded, the constructor gives up and returns the error. The running loop and the async initial connect never consult it. Default: 300000 (5 min). Setting this enables initial_connect_retry=on implicitly; see below.

  • initial_connect_retry — whether the client retries the initial connect attempt on failure.

    • off (default, alias false) — fail fast on initial connect failure.
    • on (aliases sync, true) — retry synchronously on the user thread, up to reconnect_max_duration_millis.
    • async — return the Sender immediately; the I/O thread retries in the background indefinitely, surfacing only genuine terminal failures (auth reject, durable-ack mismatch) via the error inbox.

    Implicit promotion. Setting any explicit reconnect_* key without also choosing an initial_connect_retry mode promotes initial_connect_retry to on automatically, so the budget also covers the first connect attempt — without the promotion, reconnect_max_duration_millis would be inert. To keep fail-fast behaviour on the first connect while still tuning the backoff, set initial_connect_retry=off explicitly; the explicit setting wins.

  • close_flush_timeout_millisclose() blocks up to this many milliseconds waiting for buffered frames to drain. Set to 0 or -1 for fast close (skip the drain). The default differs by client: 60000 (60 s) on Java and .NET, 5000 (5 s) on Rust, C, C++ and Python, which share the same Rust core.

    This is the shutdown data-loss window. Setting it to 0 skips the drain entirely and drops un-ACKed batches on every clean shutdown.

Auth failures during reconnect (authentication rejected, version mismatch, durable-ack mismatch, non-101 upgrade without a role hint) are immediately terminal — the loop does not retry them.

Egress failover

These keys control the per-Execute() reconnect loop on the QWP query client. Each query has its own budget; the loop resets between queries. Requires QuestDB Enterprise (multi-host).

  • failover — master switch. on (default) or off. When off, transport errors surface directly through onError without retry.
  • failover_max_attempts — cap on reconnects per Execute() (initial attempt + N − 1 failovers). Default: 8.
  • failover_backoff_initial_ms — first post-failure sleep. Default: 50.
  • failover_backoff_max_ms — cap on per-attempt sleep. Default: 1000 (1 s).
  • failover_max_duration_ms — total wall-clock budget per Execute(). Default: 30000 (30 s). Set to 0 for unbounded.

Durable ACK

Applies to: ingress.

QuestDB Enterprise

Durable ACK requires QuestDB Enterprise. OSS is single-node and does not ship WALs off-box, so the server-side durability-acknowledgement signal that drives this protocol is enterprise-only.

QuestDB Enterprise ships Write-Ahead Logs (WALs) from the primary to an object store or another file system — typically over the network. After durably shipping a WAL, the server emits a STATUS_DURABLE_ACK frame to the store-and-forward client; the client marks that frame's FSN as durable only after this acknowledgement arrives.

The benefit: if the primary dies before shipping a WAL, the client still holds the corresponding frames in its SF buffer and replays them against the new primary on failover — closing the data-loss window that a transport-level OK ACK alone cannot close.

  • request_durable_ack — when on, the client gates trim on STATUS_DURABLE_ACK frames from the server, suppressing OK-driven trim. Default: off.
  • durable_ack_keepalive_interval_millis — interval at which the client emits keepalive PINGs while waiting for durable-ack frames. Required because the server only flushes pending durable acks on inbound recv events. Default: 200 (ms). Set to 0 or a negative value to disable.

See the QWP Egress (WebSocket) wire protocol for the underlying mechanism.

Query client keys

Applies to: egress (query client).

The QWP query client's connect string (the egress / QwpQueryClient path) accepts these keys. The Sender (ingress) silently consumes the same keys so that the Sender and the QwpQueryClient can share a single connect string without an "unknown configuration key" error — the Sender does not interpret the values. Range, enum, and type checks happen on the egress side; the Sender silently accepts even a value the QwpQueryClient parser would reject.

  • compression — result-batch compression the client advertises. Options: raw (default — no compression; the client omits the accept-encoding header, so pre-compression servers see an unchanged handshake), zstd (demand zstd), auto (accept zstd if the server offers it).
  • compression_level — zstd level hint. Range 122 (server clamps to 19). Default 1 — the cheapest server-side CPU; raise it if you measure a meaningful ratio improvement on your payload and the server has the headroom. Ignored when compression=raw.
  • initial_credit — byte-credit flow-control budget. 0 (default) means unbounded: the server streams as fast as the network allows. Set a non-zero budget to bound server push on a memory-constrained client.
  • max_batch_rows — upper bound on rows per result batch. Range 1-1048576; out-of-range values fail at parse time. Defaults to the server's own limit when unset.
  • client_id — free-form client identifier sent on the upgrade as X-QWP-Client-Id, for example java/1.0.2. Default is client-specific.
  • query_close_timeout_ms — bounds the close-path cleanup drain (closing a cursor mid-result-set, breaking out of iteration) before the client declares the connection desynced and discards it. Positive integer milliseconds; default 5000 (5 s).
  • buffer_pool_size — number of decoded result-batch buffers the I/O thread keeps in rotation. Sets the in-flight window between the receive/decode loop and the user's onBatch callback: the I/O thread decodes at most this many batches ahead of the consumer. Default: 4. Minimum: 1 (no read-ahead — the I/O thread waits for each releaseBuffer() call before decoding the next batch). Each buffer reserves about 64 KiB of native scratch, so raising the value grows pinned memory linearly. When the pool drains, the I/O thread parks and the TCP receive window closes, applying back-pressure to the server. Set it before connect().

Equivalent options exist on the query client's builder API (for example, WithQwpQueryCompression, WithQwpQueryCompressionLevel, WithQwpQueryInitialCredit in the Go client). See the client library page for the per-language names.

Connection pool

Applies to: the pooled facade (QuestDB.connect, questdb::pool, QuestDb::connect, questdb.connect, qdb.NewQuestDB, QuestDBClient.Connect).

Every client now leads with a pooled facade, so these keys are a first-contact concern. The Sender and query-client parsers accept and ignore them; the facade reads them off the string. Each has an equivalent builder setter, and an explicit setter always wins over the string.

  • sender_pool_min — senders kept open even when idle. 0 lets the pool close them all. Default: 1.
  • sender_pool_max — maximum senders the pool opens. Default: 4.
  • query_pool_min — query clients kept open even when idle. Default: 1.
  • query_pool_max — maximum query clients the pool opens, which also caps total in-flight queries. Default: 4.
  • acquire_timeout_ms — how long a borrow waits for a free connection once the pool is at max, before throwing. Default: 5000.
  • idle_timeout_ms — how long an unused connection stays open before the housekeeper closes it, never going below min. 0 keeps idle connections forever. Default: 60000.
  • max_lifetime_ms — maximum age of a connection; the housekeeper closes and reopens older ones once idle. 0 means no age limit. Default: 1800000 (30 min).
  • housekeeper_interval_ms — how often the housekeeper checks for idle and over-age connections. Default: 5000.
  • lazy_connect — when on, the pool defers opening its first connection until the first borrow, so construction succeeds against a server that is down. This is the supported way to tolerate a server that starts after your application. Default: off.

Error handling

Applies to: ingress and egress.

The QWP / WebSocket I/O loop reports errors via an asynchronous inbox consumed by the application.

  • error_inbox_capacity — bounded capacity for async error notifications. Must be ≥ 16. Overflow drops the oldest entry and bumps a droppedErrorNotifications counter. Default: 256.
Accepted, but not applied by every client

Every client's parser accepts the six on_*_error keys below, but only clients that implement the policy layer act on them. In the Java reference client they are currently accepted no-ops — setting on_write_error=retriable_other parses cleanly and changes nothing. .NET does implement them, via SenderErrorPolicy and SenderErrorCategory. The category table and precedence model below describe the target contract.

The following per-category keys select the error policy for each class of server rejection. There is no drop policy: the client never silently discards data. The client either replays a rejected batch — retriable recycles the connection and replays from the acknowledged watermark; retriable_other does the same but rotates to the next endpoint (the node cannot serve writes at all) — or halts loudly with the bytes preserved in the store-and-forward log (terminal). A frame that the server keeps rejecting with no ack progress escalates to a terminal via the poison-frame detector (max_frame_rejections, default 4).

  • on_server_error — global default for server-reject status frames. Accepts auto | terminal | retriable | retriable_other. Default: auto (applies the built-in per-category defaults listed below).
  • on_schema_error — schema-validation errors. Default: terminal (deterministic under byte-identical replay).
  • on_parse_error — malformed-payload errors. Default: terminal.
  • on_internal_error — unexpected server-side faults. Default: retriable.
  • on_security_error — ACL denial on a writable node. Default: terminal.
  • on_write_error — transient write failures (disk pressure, suspended table). Default: retriable.
  • max_frame_rejections — poison-frame detector threshold: consecutive server rejections (retriable NACK, or non-orderly close after a send) of the same head-of-line frame, with no ack progress in between, before the sender latches a terminal instead of replaying forever. Integer ≥ 1; default 4.

Resolution precedence, from highest to lowest (as documented on SenderError.Policy):

  1. Builder error-policy resolver — full programmatic control.
  2. Builder per-category policy override.
  3. The connect-string per-category key (e.g. on_schema_error) — overrides the global default when set.
  4. on_server_error — the global default; when left at auto the built-in per-category defaults above apply.

PROTOCOL_VIOLATION is always terminal and UNKNOWN always retriable (fail open: a status byte from a newer server degrades to retry, not to a dead sender); neither can be overridden. Per-client wiring of the override surface may lag the spec — check your client's documentation for which of the resolver / per-category / connect-string layers it exposes. For the full model see the NACK policy design and the SenderError.Policy docs in the client source.

Key index

Alphabetical list of every option. The Section column links to the full description and behaviour notes.

KeyTypeDefaultSection
acquire_timeout_msint (ms)5000Connection pool
addrhost:port[,host:port…]requiredMulti-host failover
auth_timeout_msint (ms)15000Authentication
auto_flushenum (on / off)on (Rust: only off)Auto-flushing
auto_flush_bytessizeJava 0 (off) / .NET 8m (Rust: rejected)Auto-flushing
auto_flush_intervalint (ms) / off100 (Rust: rejected)Auto-flushing
auto_flush_rowsint / off1000 (Rust: rejected)Auto-flushing
buffer_pool_sizeint (≥ 1)4Query client keys
catch_up_cap_gap_min_escalation_window_millisint (ms)300000 (5 min)Store-and-forward
client_idstringclient-specificQuery client keys
close_flush_timeout_millisint (ms)Java/.NET 60000 / Rust, C, C++, Python 5000Ingress reconnect
compressionenum (raw / zstd / auto)rawQuery client keys
compression_levelint (122)1Query client keys
connect_timeoutint (ms, > 0)unsetAuthentication
connection_listener_inbox_capacityint (≥ 1)64 (Java) · 256 (Go, .NET) · not supported by Rust, C/C++, PythonError handling
drain_orphansenum (on / off)offStore-and-forward
durable_ack_keepalive_interval_millisint (ms)200Durable ACK
error_inbox_capacityint (≥ 16)256Error handling
failoverenum (on / off)onEgress failover
failover_backoff_initial_msint (ms)50Egress failover
failover_backoff_max_msint (ms)1000Egress failover
failover_max_attemptsint8Egress failover
failover_max_duration_msint (ms)30000Egress failover
init_buf_sizesize65536 (64 KiB)Buffer sizing
initial_connect_retryenum (off / on / async)off (auto-promoted to on when any explicit reconnect_* key is set)Ingress reconnect
initial_creditint (bytes)0 (unbounded)Query client keys
housekeeper_interval_msint (ms)5000Connection pool
idle_timeout_msint (ms)60000 (0 ⇒ infinite)Connection pool
lazy_connectenum (on / off)offConnection pool
max_background_drainersint4Store-and-forward
max_batch_rowsint (11048576)server defaultQuery client keys
max_lifetime_msint (ms)1800000 (0 ⇒ infinite)Connection pool
max_buf_sizesize104857600 (100 MiB)Buffer sizing
max_datagram_sizesize(UDP) below typical MTUBuffer sizing
max_name_lenint127Buffer sizing
max_frame_rejectionsint (≥ 1)4Error handling
on_internal_errorenumretriableError handling
on_parse_errorenumterminalError handling
on_schema_errorenumterminalError handling
on_security_errorenumterminalError handling
on_server_errorenumautoError handling
on_write_errorenumretriableError handling
passstringunsetAuthentication (alias of password)
passwordstringunsetAuthentication
poison_min_escalation_window_millisint (ms)5000Error handling
query_close_timeout_msint (ms)5000Query client keys
query_pool_maxint4Connection pool
query_pool_minint1Connection pool
reconnect_initial_backoff_millisint (ms)100Ingress reconnect
reconnect_max_backoff_millisint (ms)5000Ingress reconnect
reconnect_max_duration_millisint (ms)300000 (5 min)Ingress reconnect
request_durable_ackenum (on / off)offDurable ACK
sender_idstringdefaultStore-and-forward
sender_pool_maxint4Connection pool
sender_pool_minint1Connection pool
sf_append_deadline_millisint (ms)30000 (30 s)Store-and-forward
sf_dirpathunset (memory mode)Store-and-forward
sf_durabilityenum (memory / periodic)memory (.NET: memory only)Store-and-forward
sf_max_segment_bytessize4 MiBStore-and-forward
sf_max_total_bytessize128 MiB mem / 10 GiB SFStore-and-forward
sf_sync_interval_millisint (ms)5000Store-and-forward
targetenum (any / primary / replica)anyMulti-host failover
tls_rootspathsystem trust storeTLS
tls_roots_passwordstringunset (JKS / PKCS#12 only)TLS
tls_verifyenum (on / unsafe_off)onTLS
tokenstringunsetAuthentication
transactionenum (on / off)offStore-and-forward
userstringunsetAuthentication (alias of username)
usernamestringunsetAuthentication
zonestringunsetMulti-host failover
Per-client divergence

All clients share one option vocabulary, not one set of defaults. Where a default differs it is split above; auto_flush_bytes, close_flush_timeout_millis and sf_durability are the ones that bite most often. Do not assume a value read here applies to your language without checking its client page.