pgcat
The Rust-powered PostgreSQL pooler built for load balancing, failover and sharding
pgcat is an open source PostgreSQL connection pooler and proxy that sits between your application and your database cluster. It implements the PostgreSQL wire protocol, so ordinary drivers connect to it exactly as they would to Postgres itself — no special client library required. Written in Rust on the Tokio runtime, a single process can use several CPU cores, route read queries to replicas while sending writes to the primary, and reroute traffic around servers that fail a health check. This site gathers plain-English explanations, configuration notes and troubleshooting help for anyone evaluating or already running pgcat.
Routing layer · listening on port 6432
$ psql -h 127.0.0.1 -p 6432 -c 'SELECT 1' SET SERVER ROLE TO 'replica'; SHOW DATABASES; -- admin db
Easy to Understand
Pooling modes, query routing and configuration explained in plain language, for people who simply need pgcat working correctly.
Feature Focused
Coverage of what actually matters day to day: transaction pooling, read/write splitting, failover, statistics and the experimental sharding work.
Organised Resources
Configuration notes, admin commands and monitoring pointers collected in one place instead of scattered across issues and blog posts.
User Friendly
Guidance written both for first-time users and for teams migrating an existing PgBouncer-style deployment onto pgcat.
What Is pgcat?
pgcat is an open source connection pooler and proxy for PostgreSQL. It sits between your application and one or more Postgres servers, accepting client connections on its own port and handing out a much smaller, reused set of server connections behind the scenes. Because it speaks the PostgreSQL wire protocol, applications connect to it with the drivers they already use.
Pooling matters because every Postgres backend is a separate operating system process with its own memory. A few hundred mostly-idle application connections consume resources that would be better spent answering queries. A pooler multiplexes many short-lived client connections onto a stable, bounded set of server connections, which keeps the database predictable under bursty traffic.
Where pgcat goes beyond a classic pooler is routing. Given a primary and one or more replicas, it can inspect incoming statements with a built-in query parser and send SELECT traffic to replicas while directing writes and explicit transactions to the primary. Clients can also take control themselves using extended SQL such as SET SERVER ROLE TO 'replica'. Servers that fail a health check are temporarily banned, so traffic reroutes around them without any application change.
The project is written in Rust on the Tokio asynchronous runtime, so one process can spread work across multiple CPU cores rather than relying on several copies of a single-threaded daemon. It exposes PgBouncer-compatible admin databases named pgcat and pgbouncer for familiar SHOW commands, plus an HTTP endpoint that publishes Prometheus metrics for dashboards and alerting. pgcat is distributed under the MIT license.
Drop-in connection point
Point an existing connection string at the pooler's host and port. The protocol on the wire does not change.
Routing decisions built in
Read/write splitting, replica load balancing and failover are handled by the pooler rather than by your application code.
Multicore by design
The Tokio runtime lets a single pgcat process spawn several workers and use the machine it runs on.
Editorial note: pgcat.org is an independent informational resource about the open source pgcat project. It is not the official project website and is not affiliated with, endorsed by, or operated by the pgcat maintainers or PostgresML. Always confirm details against the project’s own repository and configuration documentation for the exact version you run.
pgcat Features
The capabilities below are the ones people most often come looking for. Feature status is taken from the project’s own documentation, which distinguishes clearly between stable and experimental functionality.
Transaction & Session Pooling
Transaction mode is the default: a client holds a server connection only for the length of one transaction, then releases it back. Session mode keeps one server per client connection when you need prepared statements, SET or advisory locks. Both are documented as stable, with extra care taken around badly behaved clients and abandoned transactions.
Read/Write Query Routing
With a primary and replicas configured, the query parser reads each statement and sends SELECT queries to a replica while routing writes and explicit transactions to the primary. When the parser cannot be sure, a client can override the decision with SET SERVER ROLE TO 'primary', 'replica', 'auto' or 'any'.
Failover & Health Checks
Every server is validated with a very fast check query before it is handed to a client, and its health is watched on each query it processes. Unreachable servers are banned for a configurable ban_time so traffic reroutes to the rest of the pool. If all servers become banned the list clears, and the primary is never banned.
Multi-threaded Rust Runtime
pgcat is written in Rust and built on the Tokio asynchronous runtime, so one process spreads work across CPU cores instead of running many single-threaded copies. The published container image is configured to spawn four workers, which makes four CPUs a sensible starting point; the worker count is adjustable.
Statistics, Admin & Prometheus
Pooler statistics are queryable through admin databases called pgcat and pgbouncer, so familiar commands such as SHOW DATABASES keep working. Metric names deliberately mirror PgBouncer's for comparability. An HTTP endpoint exposes the same data to Prometheus, and a starter Grafana dashboard ships in the repository.
Sharding & Mirroring
Opt-in features let pgcat spread queries across shards using the same PARTITION BY HASH function Postgres uses for declarative partitioning. Shards can be chosen with SET SHARD, SET SHARDING KEY, SQL comments, or automatic key detection. Mirroring duplicates traffic to a second database to prewarm or test it.
How pgcat Works
Four stages describe the journey of a single query, from the moment your application opens a socket to the moment the server connection returns to the pool.
Your application connects
Instead of pointing at Postgres directly, the connection string targets the pooler’s host and port. Because pgcat implements the PostgreSQL wire protocol, psql, libpq-based drivers and ORMs treat it as an ordinary server.
Authentication and checkout
The client authenticates against the pooler, then a server connection is checked out from the pool. In transaction mode that lease lasts for one transaction; in session mode it lasts for the whole client session.
The query is routed
The query parser decides whether the statement belongs on the primary or a replica, and explicit directives such as SET SERVER ROLE or SET SHARD can override it. Servers that recently failed a health check are skipped.
Release and record
Once the transaction commits, the server connection returns to the pool for the next client. Counters are updated and become visible through the admin databases and the Prometheus metrics endpoint.
Why People Search for pgcat
Search traffic around the term pgcat is dominated by practical questions rather than marketing curiosity. Most visitors are engineers who already run PostgreSQL, have hit a connection limit or a read-scaling problem, and want to know whether this particular pooler solves it without adding operational risk.
A smaller group arrives from comparison articles and is trying to decide between pgcat and a long-established pooler. Those readers usually care about three things: whether the feature they need is stable rather than experimental, how configuration differs from what they already run, and what happens when a server goes away in the middle of the night.
The short version: people searching for pgcat are usually mid-way through a decision, not at the start of one. This page is organised so the specific answer is reachable without reading everything above it.
What pgcat actually is
Confirming it is a pooler and proxy, not a Postgres fork or an extension.
How it compares
Weighing it against a familiar single-threaded pooler before committing.
Configuration syntax
Finding the TOML keys for pools, users, servers and pool sizes.
Read/write splitting
Understanding how SELECT traffic reaches replicas without app changes.
Sharding status
Checking which sharding features are stable and which are experimental.
Fixing something
Diagnosing auth failures, banned replicas or settings that will not stick.
pgcat Compatibility
Compatibility depends on which side of the pooler you are looking at, and some behaviour varies by version. The summary below reflects what the project documents; treat the repository for your release as the authority.
Clients and drivers
- Anything speaking the PostgreSQL wire protocol
- psql, libpq-based drivers and common ORMs
- Client authentication using MD5
- Optional TLS between client and pooler
PostgreSQL servers
- Server authentication with MD5 or SCRAM-SHA-256
- Optional TLS from pooler to server
- Primary and replica roles per pool
- auth_query passthrough instead of stored passwords
Deployment targets
- Official container image published by the project
- Helm chart included in the repository
- systemd unit file for host installations
- Build from source with a stable Rust toolchain
Known mode limits
- Transaction mode: no prepared statements
- Transaction mode: SET and advisory locks unsupported
- Use SET LOCAL and pg_advisory_xact_lock instead
- Session mode behaves close to a direct connection
Version caveat: feature status and configuration keys change between releases. Transaction pooling, session pooling, load balancing, failover, statistics, TLS, authentication and live configuration reloading are documented as stable, while sharding, automatic sharding and mirroring are marked experimental and must be enabled deliberately. Read the configuration reference that matches the tag you deploy rather than assuming defaults carry over.
How to Use pgcat
Once the pooler is running, day-to-day use comes down to six habits. None of them require changes to application code beyond the connection string.
Point the connection string at the pooler
Replace the database host and port in your application configuration with the pooler’s. Examples in the project use port 6432. Nothing else about the connection needs to change.
Choose a pooling mode per pool
Leave transaction mode on for ordinary web workloads. Move a pool to session mode only when it genuinely needs prepared statements, SET or advisory locks.
Describe your servers honestly
List each server with the correct primary or replica role and a realistic pool size per user. Wrong roles are the most common cause of traffic landing where you did not expect.
Decide how queries are routed
Rely on the query parser for the common case, and use SET SERVER ROLE for the statements where you want certainty. Shard selection works the same way with SET SHARD or SET SHARDING KEY.
Watch the pool
Connect to the pgbouncer or pgcat admin database and run SHOW commands, and scrape the Prometheus endpoint so you can see waiting clients and server bans historically, not just live.
Reload rather than restart
Most settings can be applied without dropping connections by sending SIGHUP or issuing RELOAD on the admin database. Only the listen host and port require a full restart.
How to Install pgcat
The outline below follows the sequence the project itself describes. Exact commands vary by platform and by release, so pair this with the README and configuration reference for the version you are installing.
Before you install: obtain binaries, images and charts only from the project’s official repository or container registry, confirm which version you are deploying, and read that release’s notes and configuration reference. Option names, defaults and feature status have all changed between releases, and a setting copied from an older guide may silently do nothing.
Requirements
A reachable PostgreSQL primary, optionally one or more replicas, a database user the pooler can authenticate as, and a free TCP port for it to listen on. You will also need either a container runtime or a stable Rust toolchain. Because the published image spawns four workers by default, four CPU cores is a reasonable baseline.
Preparation
Decide the pooling mode for each pool, the pool size per user, and whether credentials will live in the configuration file or be looked up dynamically through auth_query passthrough. If clients or servers must use encrypted connections, have the TLS material ready before you start.
Installation
Pull the official container image published by the project, or compile a release build from source with the Rust toolchain. The repository also contains a Helm chart for Kubernetes and a systemd unit file for traditional host installations. Take files only from the project's own repository or registry.
Configuration
Settings are written in TOML, conventionally in a file named pgcat.toml; a minimal example ships with the project. Define the general listen settings first, then the pools, then the users and servers inside each pool with their primary or replica roles.
Verification
Start the pooler and run a trivial query such as SELECT 1 through it with psql. Then connect to the pgbouncer admin database and run SHOW DATABASES to confirm your pools appear as configured, and check that the Prometheus metrics endpoint responds.
Updating
Change the image tag or rebuild the binary, then restart the process. Configuration-only changes do not need a restart: send SIGHUP to the process or issue RELOAD against the admin database. The listen host and port are the exceptions and always require a restart.
Built for Clusters, Not Just Connections
Read/write splitting without rewriting your application
Most teams reach for a pooler because of connection limits, then discover the harder problem is getting read traffic onto replicas. Doing that in application code means threading a second connection through every layer and hoping nobody writes through the read handle.
pgcat moves that decision into the connection layer. Configure the primary and its replicas in one pool, let the query parser classify statements, and keep a single connection string in your application. When you need to be explicit, extended SQL such as SET SERVER ROLE TO 'primary' pins the next transaction where you want it.
Live configuration reloading
Nearly every setting, including replica and sharding configuration, can be reloaded without restarting the pooler.
Prometheus and Grafana
Metrics are published over HTTP and the repository includes a starter Grafana dashboard to build on.
Auth passthrough
MD5 authentication can use an auth_query so cleartext passwords never need to sit in the config file.
pgcat Comparison
A factual side-by-side against the classic single-pooler setup many teams already run. This compares documented behaviour only — it is not a benchmark, and the right answer depends entirely on your workload.
Pooling modes
Transaction and session
Transaction and session
Both documented as stable and comparable in behaviour.
Concurrency model
Multi-threaded, Tokio runtime
Commonly a single-threaded process
Classic poolers usually scale by running several processes.
Read/write splitting
Built-in query parser
Usually handled in the application
Parser is best-effort; SET SERVER ROLE overrides it.
Failover
Health checks with timed server bans
Typically an external concern
Ban duration is configurable; the primary is never banned.
Sharding
Hash-based, opt-in
Not usually included
Marked experimental and disabled unless configured.
Statistics
Admin databases plus Prometheus endpoint
Admin console
Metric names deliberately mirror the classic pooler’s.
Implementation
Rust, MIT licensed
Commonly C
Both are free and open source.
Highlights and Things to Consider
pgcat Highlights
- Free and open source under the MIT license.
- One process uses multiple CPU cores thanks to the Tokio runtime.
- Read/write splitting, replica load balancing and failover are built in.
- Admin database names and statistics mirror PgBouncer, easing migration.
- Almost all configuration reloads live, without dropping connections.
- Prometheus metrics and a starter Grafana dashboard are provided.
- The project documents production use at Instacart, PostgresML and OneSignal.
Things to Consider
- Sharding, automatic sharding and mirroring are marked experimental.
- Transaction mode rules out prepared statements, SET and advisory locks.
- Any pooler adds a network hop, so latency-sensitive paths need measuring.
- The query parser is best-effort and sometimes needs explicit overrides.
- Documentation lives mainly in the repository README and configuration reference.
- Check the releases page for the current version before planning an upgrade.
- Running it well means owning another service in your critical path.
Common pgcat Problems & Solutions
Six issues that come up repeatedly, with the usual cause and the first thing to try. Logs and the admin database are almost always faster than guessing.
Every query lands on the primary
Prepared statements or SET stop working
Authentication fails through the pooler
A replica keeps dropping out of rotation
Latency increased after adding the pooler
Configuration changes appear to do nothing
pgcat Tips & Best Practices
Practical habits that prevent the most common production surprises.
Do the pool size arithmetic
The maximum number of server connections from one pgcat process is the sum of pool_size across all users. Multiply that by your number of processes or pods before comparing it with the database's max_connections.
Default to transaction mode
It gives far better connection reuse. Move only the pools that genuinely need session features into session mode, rather than switching everything to avoid one awkward query.
Prefer auth_query to stored secrets
Passthrough authentication keeps password material out of your configuration file and out of the config management system that ships it around.
Wire up metrics on day one
Scrape the Prometheus endpoint before you need it and import the dashboard from the repository. Waiting clients and server bans are much easier to read as a graph than as a live SHOW command.
Treat experimental as experimental
Sharding, automatic sharding and mirroring are documented as experimental. Pilot them in a staging environment with realistic traffic before they touch anything customer-facing.
Pin the version and re-read the config docs
Deploy a specific tag rather than a floating latest, and re-check the configuration reference on every upgrade. Rehearse a live reload in staging so you trust it during an incident.
Complete pgcat Guide
A longer read for anyone weighing pgcat seriously: who it suits, how the pieces fit together, and what to watch once it is live.
Who pgcat is for
pgcat suits teams whose PostgreSQL deployment has outgrown a single instance in one of two directions: too many client connections, or too much read traffic for the primary. If you run a primary with replicas and currently choose between them in application code, the routing features are the strongest reason to look at it. If you are a single-instance shop with a well-behaved connection count, a pooler may be solving a problem you do not have yet.
It is also a natural candidate for teams already comfortable with PgBouncer-style operations. The admin database names and statistics were deliberately kept comparable, so the muscle memory of connecting to an admin database and running SHOW commands transfers directly.
The moving parts
Three concepts cover most of the system. A pool groups the servers that back one logical database, along with the users allowed to reach it. A pool mode decides how long a client holds a server connection: one transaction, or one whole session. Roles mark each server as a primary or a replica, which is what makes read/write splitting and failover possible.
Around those sit the query parser, which classifies statements so they reach the right kind of server, and the health checking that bans unreachable servers for a configurable period. The primary is deliberately exempt from banning, and if every server ends up banned the list is cleared as a safety measure against false positives.
Configuration in practice
Configuration is a TOML file, conventionally pgcat.toml, and the project ships a minimal example alongside a fuller reference. Work top-down: general settings such as the listen address and worker count first, then each pool, then the users and servers inside it. Pool sizes are defined per user, and the ceiling on server connections from one process is the sum of those sizes.
The single most valuable operational detail is live reloading. Sending SIGHUP to the process, or issuing RELOAD on the admin database, applies almost every setting without restarting — including replica and sharding configuration. The listen host and port are the documented exceptions.
Running it in production
Give the process enough cores to match its worker count; the published image is set up for four. Place it close to the database so the extra hop stays cheap, and run more than one instance behind whatever load balancing your platform provides so the pooler itself is not a single point of failure.
Instrument it early. The Prometheus endpoint plus the bundled Grafana dashboard will tell you whether clients are waiting for a server connection, which is the number that usually explains a mysterious slowdown. Alert on waiting clients and on servers being banned, not just on the process being alive.
When something else may fit better
If your driver already has a good client-side pool and your connection count is comfortable, an external pooler mostly adds a component to operate. If you need session-level features everywhere, transaction mode’s benefits largely disappear. And if your plan depends on sharding, weigh carefully that the sharding features are documented as experimental rather than stable.
Keeping up with changes
The project is actively developed, and feature status, defaults and option names move between releases. Treat the README and configuration reference at the tag you deploy as the source of truth, subscribe to the releases feed, and re-read the notes before every upgrade. Guides written against an older version — including this one — age faster than the software does.
pgcat Frequently Asked Questions
Twenty answers to the questions that come up most often. Where behaviour depends on your version, the answer says so rather than guessing.
What is pgcat?
pgcat is an open source PostgreSQL connection pooler and proxy. It accepts client connections on its own port and multiplexes them onto a smaller pool of reused server connections, while adding load balancing across replicas, failover around unhealthy servers and optional sharding. It is written in Rust, implements the PostgreSQL wire protocol, and is released under the MIT license.
How does pgcat work?
Your application connects to the pooler rather than directly to Postgres. After authentication, pgcat checks out a server connection from the pool — for one transaction in transaction mode, or the whole session in session mode. It inspects the statement to decide whether it should run on the primary or a replica, sends it, then returns the server connection to the pool and records statistics.
What are the main pgcat features?
Transaction and session pooling, load balancing of read queries across replicas, automatic failover with health checks, a multi-threaded Rust runtime, admin databases for statistics, Prometheus metrics, TLS, MD5 and SCRAM-SHA-256 authentication and live configuration reloading are all documented as stable. Sharding, automatic sharding and mirroring exist but are marked experimental.
Is pgcat easy to use?
For a straightforward pool, yes: change the host and port in your connection string, write a short TOML configuration file describing your pools, users and servers, and start the process. Complexity arrives with the advanced features. Read/write splitting needs correct server roles, and sharding needs a deliberate design decision, so those deserve time in a staging environment first.
What devices and platforms support pgcat?
pgcat is server software rather than an end-user application, so the question is really about where you run it. The project publishes a container image, includes a Helm chart for Kubernetes and a systemd unit file for host installations, and can be compiled from source with a stable Rust toolchain. On the client side, anything that speaks the PostgreSQL wire protocol can connect.
How do I install pgcat?
Pull the official container image, or build a release binary from source with the Rust toolchain. Write a pgcat.toml describing your general settings, pools, users and servers — a minimal example ships with the project. Start the pooler, then verify with a simple query through it and by running SHOW DATABASES against its admin database.
How do I update pgcat?
For a new version, change the image tag or rebuild the binary and restart the process, ideally one instance at a time so clients can reconnect elsewhere. Read the release notes first, because configuration keys and defaults change between versions. Configuration-only changes do not need an upgrade or a restart at all.
Why is pgcat not working?
Start with the logs, which usually name the problem directly. The most common causes are a configuration file that failed to parse, credentials that do not match what the server expects, a server role labelled incorrectly, or a health check failure that has temporarily banned a server. Connecting to the admin database and running SHOW commands quickly narrows it down.
What should I check before installation?
Confirm you have a reachable primary and any replicas, a database user the pooler can authenticate as, a free port to listen on, and enough CPU cores for the worker count you plan to run. Decide whether credentials will live in the config file or be resolved with auth_query, and prepare TLS material if encrypted connections are required.
Does compatibility vary by version?
Yes, and this matters more than it sounds. Feature status, option names and defaults have all changed across releases, and some capabilities are stable while others remain experimental. Always read the configuration reference from the same tag as the build you are deploying rather than relying on an older tutorial, including this page.
Where can I find pgcat resources?
The project’s own repository is the primary source: it contains the README, the configuration reference, example TOML files, a Docker Compose environment, a Helm chart and a starter Grafana dashboard. Release notes are published alongside tagged versions. This site summarises and explains that material but does not replace it.
How do I troubleshoot pgcat?
Work outward from the pooler. Read its logs, then query the admin database with SHOW commands to see pools, clients and servers. Compare what you expect with what is configured, especially server roles and pool sizes. If the pooler looks healthy, test a direct connection to Postgres to establish which side of the hop the problem sits on.
Can I uninstall pgcat?
Yes. Because it sits between your application and the database and does not modify the database itself, removing it is a matter of pointing connection strings back at Postgres directly and then stopping and deleting the pooler. Check your database’s max_connections can absorb the unmultiplexed connection count before you make the switch.
What should I do before updating?
Read the release notes for every version between yours and the target. Back up the configuration file, diff it against the new configuration reference, and apply the upgrade in staging with realistic traffic first. Roll production instances one at a time so clients can reconnect through the remaining ones.
Does pgcat require additional software?
It requires PostgreSQL servers to sit in front of, and either a container runtime or a Rust toolchain to obtain the binary. Nothing else is mandatory. Prometheus and Grafana are optional but strongly recommended, since the metrics endpoint and bundled dashboard are how you see waiting clients and server bans over time.
How can I check my current version?
Ask the running process: container images are tagged with their version, and the pooler reports version information in its startup logs. If you built from source, the tag or commit you compiled identifies it. Recording the deployed version in your own configuration management saves time during an incident.
What are common pgcat problems?
Queries all landing on the primary because server roles or the query parser are misconfigured; session state disappearing under transaction mode; authentication mismatches between the pooler and the server; replicas being banned after failed health checks; extra latency from the additional hop; and configuration edits that were never reloaded.
Where can I learn more about pgcat?
The repository README and configuration reference cover the software itself. Engineering blog posts from teams that adopted it, along with community write-ups comparing it to other poolers, give useful operational context. The project also runs a community chat for questions that the documentation does not answer.
Is pgcat.org an official website?
No. pgcat.org is an independent informational resource. It is not affiliated with, endorsed by, or operated by the pgcat maintainers or PostgresML, and it does not host or distribute the software. Everything here is a summary of publicly documented behaviour, and the project’s own repository always takes precedence where the two disagree.
What should new pgcat users know?
Three things. Transaction mode is the default and it changes what session-level SQL you can rely on. Server roles must be correct or routing will not behave as you expect. And the distinction between stable and experimental features is real — build your plans on the stable set, and treat sharding and mirroring as things to evaluate rather than assume.
Explore pgcat
Whether you are weighing a pooler for the first time or migrating an existing deployment, the guides, configuration notes and troubleshooting answers on this page are here to shorten the distance between curiosity and a working setup.