1. Project Overview & Quickstart (pgdogdev/LICENSE)
LICENSE
Open-source repository pgdogdev/LICENSE
Repository Details
- Repository: pgdogdev/LICENSE
- Primary Language: Code
Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.
2. Official Technical Reference & Guides (pgdogdev/docs)
File: README.md
PgDog Documentation
This repository contains the documentation hosted on https://docs.pgdog.dev.
Contributions
Contributions are welcome. Please open a pull request / issue with requested changes. Once the PR is merged,
you should see changes in production within a few minutes.
File: docs/administration/clients.md
icon: material/account-multiple
Client connections
PgDog provides real time statistics and information on all client connections. They can be accessed by connecting to the admin database and running the SHOW CLIENTS command:
SHOW CLIENTS;The following information is returned for each client connection to PgDog:
| Name | Description | Example |
|---|---|---|
user |
User name the client is connected as. | admin |
database |
Database name the client is connected to. | admin |
addr |
IP address of the client. | 127.0.0.1 |
port |
TCP port client is connected from. | 53002 |
state |
Real time client state, e.g. active, idle, etc. |
idle |
replication |
Replication mode if applicable. | none |
connect_time |
Timestamp when the client connected. | 2025-09-17 19:56:16.981 -07:00 |
last_request |
Timestamp of the last request from this client. | 2025-09-17 20:09:49.799 -07:00 |
queries |
Number of queries executed. | 2 |
transactions |
Number of completed transactions executed. | 2 |
transactions_2pc |
Number of two-phase commit transactions. | 0 |
wait_time |
How long the client had to wait to get a connection from the pool. This value increases monotonically if the client is waiting for a pool that's too busy to serve transactions. | 0 |
query_time |
Total time this client's queries took to run on a server. | 7.334 |
transaction_time |
Total time this client's transactions took to execute on the server, including idle in transaction time. | 7.340 |
bytes_received |
Number of bytes received over the network from the client. | 36 |
bytes_sent |
Number of bytes sent over the network to the client. | 12470 |
errors |
Number of errors the client has received, e.g. query syntax errors. | 0 |
application_name |
Application name set by the client. | psql |
memory_used |
Amount of memory used by this client connection (in bytes). | 2397 |
locked |
Whether the client connection is locked. | f |
prepared_statements |
Number of prepared statements created by this client. | 0 |
File: docs/administration/config.md
icon: material/cog
Configuration
PgDog provides real time access to its current configuration values. They can be accessed by connecting to the admin database and running the SHOW CONFIG command:
SHOW CONFIG;The following configuration parameters are available and their current values:
| Name | Example |
|---|---|
auth_type :material-link: |
scram |
ban_timeout :material-link: |
5m |
checkout_timeout :material-link: |
1s |
client_idle_timeout :material-link: |
18446744073709551615ms |
connect_attempt_delay :material-link: |
0ms |
connect_attempts :material-link: |
1 |
connect_timeout :material-link: |
1s |
cross_shard_disabled |
false |
default_pool_size :material-link: |
10 |
dns_ttl |
default |
dry_run :material-link: |
false |
healthcheck_interval :material-link: |
30s |
healthcheck_timeout |
5s |
host :material-link: |
0.0.0.0 |
idle_healthcheck_delay :material-link: |
5s |
idle_healthcheck_interval :material-link: |
30s |
idle_timeout :material-link: |
1m |
load_balancing_strategy :material-link: |
round_robin |
log_connections :material-link: |
true |
log_disconnections :material-link: |
true |
min_pool_size :material-link: |
1 |
mirror_exposure :material-link: |
1.0 |
mirror_queue :material-link: |
128 |
openmetrics_namespace :material-link: |
pgdog_ |
openmetrics_port :material-link: |
9090 |
passthrough_auth :material-link: |
disabled |
pooler_mode :material-link: |
transaction |
port :material-link: |
6432 |
prepared_statements :material-link: |
extended |
prepared_statements_limit :material-link: |
500 |
pub_sub_channel_size :material-link: |
4098 |
query_cache_limit |
500 |
query_log |
default |
query_timeout :material-link: |
1s |
read_write_split :material-link: |
include_primary |
read_write_strategy |
aggressive |
rollback_timeout :material-link: |
1s |
shutdown_timeout :material-link: |
1m |
tls_certificate :material-link: |
default |
tls_private_key :material-link: |
default |
tls_server_ca_certificate :material-link: |
default |
tls_verify :material-link: |
prefer |
two_phase_commit :material-link: |
false |
two_phase_commit_auto :material-link: |
default |
workers :material-link: |
2 |
tcp_congestion_control |
default |
tcp_interval |
default |
tcp_keepalive |
true |
tcp_retries |
default |
tcp_time |
default |
tcp_user_timeout |
default |
File: docs/administration/index.md
icon: material/monitor-dashboard
Administration overview
PgDog keeps track of clients, servers and connection pools. It provides real time statistics on its internal operations for system
administrators to keep track of and integrate with monitoring tools like Datadog.
Just like pgbouncer, PgDog has a special "admin" database clients can connect to and run custom SQL commands
to get statistics.
Admin database
The admin database name is configurable. By default, the database is called admin. It supports a number of commands, documented below.
Commands
| Command | Description |
|---|---|
SHOW CLIENTS |
Clients connected to PgDog with real time statistics. |
SHOW SERVERS |
Server connections made by PgDog to PostgreSQL. |
SHOW POOLS |
Connection pools used to multiplex clients and servers. |
SHOW CONFIG |
Currently loaded values from pgdog.toml. |
SHOW STATS |
Connection pools statistics. |
SHOW PEERS |
List of PgDog processes running on the same network. Requires service discovery to be enabled. |
RELOAD |
Reload configuration from disk. See pgdog.toml and users.toml for which options can be changed at runtime. |
FORCE_RELOAD |
Reload configuration from disk and terminates any in-flight transactions. Guarantees that all transactions following the completion of this command are sent to the new connection pools. |
RECONNECT |
Re-create all server connections using existing configuration. |
PAUSE |
Pause all pools. Clients will wait for connections until pools are resumed. Can be used for gracefully restarting PostgreSQL servers. |
RESUME |
Resume all pools. Clients are able to check out connections again. |
SHOW PREPARED |
List prepared statements currently in the cache. |
SHOW QUERY_CACHE |
List statements currently in the AST cache used for query routing. |
MAINTENANCE |
Pause all queries to synchronize configuration changes across multiple instances of PgDog. |
SHOW REPLICATION |
Show the status of PostgreSQL replication for each database, including replica lag. |
RESHARD |
Reshard a database online and cut over traffic automatically. Returns a background task_id. |
COPY_DATA |
Copy and reshard data to a destination cluster, then stream changes. Returns a background task_id. |
SCHEMA_SYNC |
Synchronize schema for a given phase between source and destination. Returns a background task_id. |
REPLICATE |
Stream changes from source to destination (schema and data must already be synced). Returns a background task_id. |
CUTOVER |
Cut traffic over to the destination cluster for a running replication task. |
SHOW TASKS |
List background tasks (resharding, copy, replication, schema sync) with their status and elapsed time. |
STOP_TASK |
Stop a running background task by its task_id. |
Shutting down PgDog
When you need to shutdown PgDog, e.g. to deploy a new version, you can do so gracefully by issuing SIGINT (e.g. Ctrl-C) to the pgdog process.
PgDog will stop listening for new connections and give connected clients some time to finish their transactions and disconnect.
The amount of time PgDog will wait is configurable. By default, PgDog will wait 60 seconds.
Example
$ pkill pgdog -SIGINTFile: docs/administration/maintenance_mode.md
icon: material/wrench
Maintenance mode
Maintenance mode pauses queries from all clients so you can synchronize configuration changes across multiple instances of PgDog. This is useful if you're changing the sharding options.
How it works
You can turn on maintenance mode by connecting to the admin database and running this query:
MAINTENANCE ON;Clients that are currently executing a transaction will be allowed to finish, while all others will be immediately paused. Pausing traffic has the effect of holding query requests inside PgDog's network buffer. To the client, this will seem like the proxy isn't responding.
!!! note
Before enabling maintenance mode, make sure to set the application-level timeouts high enough as to avoid erroring out.
During maintenance mode, you can perform live configuration changes. The following flow is typical and, if performed quickly, won't cause errors or downtime:
- Make changes to
pgdog.tomland/orusers.toml - Enable maintenance mode
- Reload config on all instances of PgDog
- Disable maintenance mode
Turn off maintenance mode
Turning off maintenance mode and resuming all queries can be done with a query:
MAINTENANCE OFF;File: docs/administration/pools.md
icon: material/pool
Connection pools
PgDog provides real time statistics and information on its connection pools. You can view them by connecting to the admin database and running the SHOW POOLS command:
SHOW POOLS;The following information is returned for each connection pool (user/database pair) managed by PgDog:
| Name | Description | Example |
|---|---|---|
id |
Pool identifier. | 1 |
database |
Name of the PostgreSQL database. | myapp_prod |
user |
User used to connect to the database. | app_user |
addr |
IP address or DNS name of the PostgreSQL server. | 10.0.1.5 |
port |
TCP port of the PostgreSQL server. | 5432 |
shard |
Shard identifier. | 0 |
role |
Database role. | primary |
cl_waiting |
Number of clients waiting for a connection from this pool. | 3 |
sv_idle |
Number of idle server connections in the pool. | 8 |
sv_active |
Number of checked out (used) server connections in the pool. | 12 |
sv_idle_xact |
Number of idle-in-transaction server connections in the pool. | 0 |
sv_total |
Total number of server connections in the pool. | 20 |
maxwait |
How long the first (oldest) client in the queue has waited, in seconds. | 30 |
maxwait_us |
Microsecond part of the maxwait value. |
30000000 |
pool_mode |
Connection pooling mode. | transaction |
paused |
The pool is paused and won't issue connections until resumed. | f |
banned |
The pool is blocked from serving more clients. | f |
errors |
Number of connections returned to the pool in a bad state, e.g. network connectivity broken. | 0 |
re_synced |
Number of connections that have been re-synchronized. | 2 |
out_of_sync |
Number of connections returned to the pool by clients that left it in a bad state, e.g. by issuing a query and not waiting for the result. | 0 |
online |
Whether the pool is online. | t |
replica_lag |
Replication lag for replica connections. | 0 |
schema_admin |
Whether this connection pool is used for schema synchronization. | f |
File: docs/administration/replication.md
icon: material/content-copy
Replication
PgDog provides a real time view into PostgreSQL replication for the purposes of monitoring replication delay and performing query traffic failover.
You can view this data by connecting to the admin database and running this query:
SHOW REPLICATION;The following information is returned for each database:
| Name | Description | Example |
|---|---|---|
id |
Connection pool identifier matching pools in SHOW POOLS. |
4 |
database |
Name of the PostgreSQL database. | postgres |
user |
User used to connect to the database. | postgres |
addr |
IP address or DNS name of the server. | 127.0.0.1 |
port |
TCP port of the server. | 45001 |
shard |
Shard number of the database. | 0 |
role |
Database role, either primary or replica. |
replica |
replica_lag |
Replication lag in milliseconds. | 0 |
pg_lsn |
Current LSN (Log Sequence Number) of the database. | 0/21000168 |
lsn_age |
Time since the last transaction in milliseconds. | 2245 |
pg_is_in_recovery |
Whether the database is in recovery mode (t = true, f = false). |
t |
File: docs/administration/servers.md
icon: material/server
Server connections
PgDog provides real time statistics and information on all connections to PostgreSQL databases. They can be accessed by connecting to the admin database and running the SHOW SERVERS command:
SHOW SERVERS;The following information is returned for each connection from PgDog to a PostgreSQL database:
| Name | Description | Example |
|---|---|---|
database |
Name of the PostgreSQL database. | shard_0 |
user |
User used to connect to the database. | pgdog |
addr |
IP address or DNS name of the server. | localhost |
port |
TCP port of the server. | 5432 |
state |
Server connection state, e.g. active, idle in transaction, etc. |
receiving data |
connect_time |
Timestamp when the connection was established. | 2025-09-17 19:55:37.958 -07:00 |
request_time |
Timestamp of the last request on this connection. | 2025-09-17 19:55:37.965 -07:00 |
remote_pid |
Process ID of the PostgreSQL backend process. | 1384 |
transactions |
Number of transactions completed by this server connection. | 1 |
queries |
Number of queries executed by this server connection. | 1 |
rollbacks |
Number of automatic rollbacks executed on this server connection by PgDog to clean up after idle transactions left by clients. | 0 |
prepared_statements |
Number of prepared statements created on this server connection. | 0 |
healthchecks |
Number of healthchecks executed on this server connection. | 0 |
errors |
Number of errors this connection has produced e.g. syntax errors. | 0 |
bytes_received |
Number of bytes received over the network. | 60 |
bytes_sent |
Number of bytes sent over the network. | 56 |
age |
How long ago this connection was created (in ms). | 851 |
application_name |
Application name set by the client connection. | PgDog Pub/Sub Listener |
memory_used |
Amount of memory used by this connection (in bytes). | 1787 |
File: docs/administration/tasks.md
icon: material/format-list-checks
Background tasks
Long-running operations like resharding don't block the connection that started them. Instead, RESHARD, COPY_DATA, REPLICATE, and SCHEMA_SYNC each return a task_id and run in the background. SHOW TASKS is how you track those tasks: it reports their lifecycle status and progress, lets you find the task_id to pass to STOP_TASK or CUTOVER, and surfaces failures.
Run it on the admin database:
SHOW TASKS;!!! note "Admin database tasks only"
SHOW TASKS lists the background tasks running inside the same PgDog process. The equivalent CLI commands (pgdog data-sync, pgdog schema-sync) spawn their own process in the foreground instead, and block until they finish or are stopped with SIGINT (or SIGTERM).
=== "Output"
-[ RECORD 1 ]+---------------------------------- id | 14 scope | root type | reshard prod -> prod_sharded status | running inner_status | syncing data started_at | 2026-06-30 18:02:11.004 UTC updated_at | 2026-06-30 18:05:42.119 UTC elapsed | 00:03:31:115 elapsed_ms | 211115 -[ RECORD 2 ]+---------------------------------- id | scope | subtask type | copy_data prod -> prod_sharded status | running inner_status | started_at | 2026-06-30 18:02:30.550 UTC updated_at | 2026-06-30 18:05:42.119 UTC elapsed | 00:03:11:569 elapsed_ms | 191569
Tasks are ordered by creation date, starting at the oldest.
Columns
| Column | Description |
|---|---|
id |
The task ID. This is the handle you pass to STOP_TASK and CUTOVER. Only root tasks have an ID; subtasks share their parent's ID and leave this column empty. |
scope |
root for a top-level task, subtask for a step it spawned (e.g. the copy_data and replication steps of a reshard). |
type |
What the task is, usually with the source and destination databases, e.g., reshard, copy_data, replication, replication [...] (reverse), schema_sync(pre). |
status |
The lifecycle status of the task. See Statuses. |
inner_status |
Fine-grained progress within the current status. See Progress. For a finished or failed task, this shows the last progress it reported. |
started_at |
When the task started. |
updated_at |
When the task last changed status or progress. For a finished task this is when it finished. |
elapsed / elapsed_ms |
How long the task ran. For a completed task this is the total run time (measured to updated_at). |
Statuses
The status column describes where the task is in its lifecycle:
| Status | Meaning |
|---|---|
started |
The task is being set up. |
running |
The task is actively working. |
cancelling |
A STOP_TASK was requested and the task is winding down cooperatively. |
finished |
The task completed successfully. |
cancelled |
The task was stopped before completing. |
failed: <error> |
The task errored. The error message is included in the status. |
panicked: <error> |
The task hit an unexpected internal error. |
finished, cancelled, failed, and panicked are terminal. Terminal tasks stay listed with their final status (and last progress) for a while so you can inspect the outcome, then they're pruned automatically.
Progress
The inner_status column shows what the task is doing within its current status. The values depend on the task type:
| Task | Progress values |
|---|---|
reshard |
syncing schema โ syncing data โ finalizing schema โ replicating |
copy_data |
(no sub-status; track copy progress with SHOW TABLE_COPIES) |
replication |
replicating โ cutting over (or rolling back for a reverse stream) / stopping |
schema_sync |
loading schema โ syncing tables โ creating indexes (or syncing cutover schema) |
Finding the right ID
STOP_TASK and CUTOVER always operate on the parent ID:
- A
RESHARDorCOPY_DATAshows as aroottask with its child steps listed assubtaskrows. Target the root ID, not a subtask; subtask rows have an emptyidon purpose. - After a cutover, the reverse replication stream appears as its own
roottask of typereplication ... (reverse). Use its ID to roll back (CUTOVER) or to finalize the migration (STOP_TASK).
Spotting issues
| Symptom | What to check |
|---|---|
status is failed: ... or panicked: ... |
Read the error message in the status column, then check the PgDog logs for the full context. The task is stopped; address the cause and re-run the command. |
Task stuck at one inner_status for a long time |
Cross-reference SHOW TABLE_COPIES (during syncing data) and SHOW REPLICATION_SLOTS (during replicating) to see whether data is still flowing. |
status is cancelling and not clearing |
The task is draining its replication streams. A cutover that has already started runs to completion before the status settles. |
| Terminal task you expected to still be running | It reached a terminal state (finished/cancelled/failed). Check inner_status and updated_at to see where and when it stopped. |
Stopping a task
Stop any running task by its root id:
STOP_TASK <task_id>;This requests cancellation; the task winds down gracefully and stops appearing as running once it has actually stopped. For replication and copy tasks, a graceful stop also drops the replication slot the task created. See finalizing the migration for how this is used after a cutover.
File: docs/architecture/benchmarks.md
icon: material/chart-bar
Benchmarks
PgDog does its best to minimize its impact on database performance. Great care is taken to make sure as few operations as possible are performed
when passing data between clients and servers.
All benchmarks listed below were done on my local system (AMD Ryzen 7 5800X). Real world performance is impacted by factors like network speed, query complexity and especially by hardware used for running PgDog and PostgreSQL servers.
pgbench
The simplest way to test PostgreSQL performance is with pgbench. It comes standard with all PostgreSQL installations (Mac and Linux):
$ pgbench --version
pgbench (PostgreSQL) 16.4 (Postgres.app)A standard pgBench benchmark will run INSERT, UPDATE, SELECT and DELETE queries to get an overall view of database performance. Since we are only testing the performance of PgDog, we are going to run SELECT queries only and minimize the impact of hard disk I/O on this test.
This benchmark can be reproduced by passing the -S flag to pgbench. The results below were performed using the configuration found in pgdog.toml.
Results
Multi-threaded
Numbers below are for a single database benchmark in transaction mode. workers are set to 4, so PgDog is running 4 threads and using async I/O.
Protocol
The protocol column indicates what kind of communication protocol
pgbench is using to talk to PgDog/Postgres.
simple protocol is sending
queries with parameters included in query text. This requires Postgres
to receive only one message but has parsing overhead inside PgDog.
extended protocol separates parameters from query text. This prevents
SQL injection attacks, but PgDog is able to deduplicate statements and most parsing overhead.
prepared protocol is the fastest since pgbench is re-using the same
statements and only sends different parameters. This removes the need to parse
statements inside PgDog and Postgres.
The numbers
| Protocol | Clients | TPS | Latency |
|---|---|---|---|
| simple | 1 | 10,790.06 | 0.093 ms |
| simple | 10 | 70,661.18 | 0.137 ms |
| simple | 100 | 78,232.15 | 1.266 ms |
| extended | 1 | 11,634.29 | 0.086 ms |
| extended | 10 | 74,529.28 | 0.128 ms |
| extended | 100 | 94,584.0 | 1.045 ms |
| prepared | 1 | 17,468.19 | 0.057 ms |
| prepared | 10 | 110,942.87 | 0.084 ms |
| prepared | 100 | 119,273.2 | 0.825 ms |
Single-threaded
This benchmark ran with workers set to 0. This makes PgDog run in single-threaded mode, but still uses async I/O.
| Protocol | Clients | TPS | Latency |
|---|---|---|---|
| simple | 1 | 11,042.68 | 0.090 ms |
| simple | 10 | 30,209.56 | 0.331 ms |
| simple | 100 | 28,931.41 | 3.349 ms |
| extended | 1 | 11,702.49 | 0.085 ms |
| extended | 10 | 49,920.91 | 0.200 ms |
| extended | 100 | 47,108.79 | 2.075 ms |
| prepared | 1 | 18,222.30 | 0.055 ms |
| prepared | 10 | 53,468.63 | 0.187 ms |
| prepared | 100 | 50,441.38 | 1.943 ms |
Interpretation
1 client
Benchmarks with -c 1 (1 client) are a good baseline for what's possible under the best possible circumstances. There is no contention on resources
and PgDog effectively receives data in one socket and pushes it out the other.
10 clients
With 10 clients actively querying the database, the connection pool is at full capacity (default_pool_size is set to 10). While there are no clients waiting for connections, the pool has to serve clients without any slack in the system.
100 clients
With over 10x more clients connected than available servers, connections are fighting for resources and PgDog has to make sure everyone gets served in a fair way. Consistent throughput in this benchmark demonstrates our ability to timeshare server connections effectively.
Parser overhead
PgDog parses statements to figure out where they should go. When using simple protocol, PgDog can't cache statements (since they include parameters), so the overhead of the parser is noticeable. When using extended and prepared protocols, the cache is doing its job and the parser overhead is almost entirely eliminated.
In the real world
In production, PostgreSQL clients are expected to be mostly idle. For example, web applications spend a lot of their time parsing HTTP requests, running code and waiting on network I/O. This leaves plenty of time for PgDog (and PostgreSQL) to serve queries for thousands of clients.
Hardware impact
Benchmark results will vary widely with hardware. For example, these numbers will be better on new Apple M chips and slower on older Intel CPUs. This benchmark was ran on AMD Ryzen 7 5800X. Expect yours to vary, but the overall trend to be directionally similar.
pgbench configuration
export PGPASSWORD=pgdog
pgbench -P 1 -h 127.0.0.1 -p 6432 \
-U pgdog pgdog -c 10 -t 100000 -S \
--protocol prepared