PgBouncer 1.26.1 Fixes an Authentication Bypass. Treat the Upgrade as a Production Drill

Published on 10/17/2026•By Prakhar Bhatia
PgBouncer 1.26.1 Fixes an Authentication Bypass. Treat the Upgrade as a Production Drill

PgBouncer 1.26.1 is a security release, not a routine pooler refresh. Its most serious fix is CVE-2026-107350: under a specific SCRAM authentication path, a client that knows one SCRAM user's password could authenticate as another SCRAM user, including an administrator or backend superuser. The same release fixes two unauthenticated denial-of-service conditions.

That deserves a production change, not an emergency copy-and-restart performed without evidence. A connection pooler sits on an authentication boundary and controls how application traffic reaches a database. The job is to remove the vulnerable version quickly while keeping the change observable, reversible, and narrow enough that a separate configuration mistake does not become the incident.

Start With Scope, Not a Version Bump

The release notes describe three issues. The authentication bypass involved a second StartupMessage processed during SCRAM authentication when connecting to a non-existent database. One denial-of-service issue involved an empty option name in the startup options parameter with a particular ignore_startup_parameters configuration. The other involved packet-buffer growth when max_packet_size is above its default.

Those details matter because a security response starts with exposure, not a guess about whether an application is "probably fine." Build a short inventory before changing anything.

Find Every Running PgBouncer

Do not rely on one deployment manifest or one package manager query. Teams often have a primary pooler tier, a read-only tier, a reporting database, an older migration host, and development or staging environments that use the same credentials.

Record the hostname or workload, version, configuration path, listener address, TLS settings, authentication method, pool mode, backend role, traffic owner, and deployment method. Include anything that can receive external client traffic or shares a credential source with production.

pgbouncer --version
ps -ef | grep '[p]gbouncer'
systemctl status pgbouncer

For containers, obtain the version from the image or running process rather than assuming a mutable tag means a patched binary. Capture the image digest and the configuration revision you intend to deploy.

Identify the SCRAM Boundary

The bypass is about SCRAM users. Confirm which pools use auth_type = scram-sha-256, where the authentication secrets come from, and which roles can reach privileged backend accounts. A useful inventory includes:

  • the authentication file, query, or external identity source;
  • roles permitted to use each database alias;
  • administrative users and PostgreSQL superusers;
  • rejected-login logging and its retention period;
  • application paths that can choose a database name.

Avoid putting passwords, hashes, or live connection strings in a change ticket. The aim is to understand the route from an incoming identity to a backend role without spreading the material that protects it.

Decide What the Fix Means for Your Risk Review

An upgrade corrects the running code. It does not automatically answer whether the vulnerable path was attempted. Keep those two jobs separate.

The release describes a condition involving SCRAM, a second startup message, and a non-existent database. That is not the same as evidence that every credential has leaked. It is enough to treat PgBouncer logs, database authentication logs, and any security telemetry around unexpected database names or privileged logins as evidence worth preserving before rotation or restart policies make it disappear.

Preserve Useful Evidence First

Take a time-bounded copy of relevant PgBouncer and PostgreSQL authentication logs according to your retention policy. Note the version window, affected nodes, and the deployment time. Ask the database owner where privileged session activity is normally recorded. This lets security and operations look at the same facts later.

Do not turn a maintenance post into a claim that compromise occurred. If the review finds suspicious activity, use the incident process. If it does not, document the review and the reason for any credential action you do or do not take.

Treat Credential Rotation as a Deliberate Follow-Up

Rotation can be appropriate, particularly for high-privilege SCRAM roles or an exposure path that cannot be ruled out. It can also cause more downtime than the binary upgrade when applications, secret stores, replicas, or read-only jobs are not ready for it.

Make the decision with the identity owner and the database owner. A targeted plan usually identifies the affected role, updates the secret source, deploys consumers that can use the new secret, verifies new sessions, and only then retires the old secret. That sequence is safer than resetting every database password during the same narrow repair window.

Prepare a Change That Can Be Reversed

PgBouncer upgrades are often small operational changes, but the pooler can concentrate a large amount of traffic. Write a one-page plan that names the owner, maintenance window, affected nodes, expected client behavior, validation checks, abort conditions, and rollback version.

Drain Connections Before Stopping a Node

A restart should not begin by dropping every request on the first pooler. Remove one instance from service, wait for load balancer health checks to converge, and observe whether the remaining capacity can handle the traffic. Then let existing sessions finish where your topology and time budget permit.

The exact drain command depends on your platform. Some teams remove an endpoint from a load balancer. Others lower a deployment replica count only after readiness has been withdrawn. The important property is visible ownership: a client should stop receiving new work from the node before you terminate its pooler process.

1. Mark one pooler unavailable for new traffic.
2. Confirm traffic moves to healthy peers.
3. Wait for active client and server connections to fall.
4. Stop PgBouncer and replace the package or image.
5. Start the patched process and confirm readiness.
6. Return the node to service only after functional checks pass.

In a singleton setup, plan a short outage and communicate it. Pretending a single node has a graceful failover path is worse than scheduling a small, honest interruption.

Freeze the Configuration You Tested

Use the existing production configuration unless the release requires a change. A security release is a poor time to alter pool mode, change authentication sources, tune connection limits, and upgrade operating-system packages in one deployment.

There is one relevant release behavior to review: ignore_startup_parameters now takes precedence over tracked parameters. PgBouncer says ignore_startup_parameters = search_path restores the 1.25 behavior of ignoring search_path. Check whether that setting exists in your configuration and run the application's schema-selection paths in staging before the production rollout.

Test the Authentication Paths You Actually Use

"PgBouncer started" is only a process check. The most important verification is that the patched pooler accepts intended application connections and rejects the ones it should reject.

Use Separate Good and Bad Test Identities

Prepare a minimally privileged test role and a known-invalid credential. Do not test administrative access by passing an administrator password through an ad hoc shell command where it will be retained in history or process listings.

Run a simple transaction through every significant database alias, user class, and network route. Check a deliberately invalid login too. You are looking for a clean distinction: valid clients authenticate and reach the expected database; invalid clients fail without leaving hanging connections, unusual retries, or a confusing fallback identity.

SELECT current_user, current_database();
SELECT 1;

The queries are intentionally boring. The connection path is the test. A complex report query can hide whether a failure was authentication, routing, permissions, or SQL behavior.

Check Pool Behavior Under Short Load

Run a small representative workload after the node returns to service. Watch for client waits, backend connection growth, rejected connections, timeout spikes, and application retry rates. Compare them to a pre-change baseline rather than to an idealized zero.

For transaction pooling, include a transaction that acquires and releases a connection in the way your application normally does. For session pooling, include a request that needs session state. For each mode, test the features your own application depends on instead of importing a generic benchmark that never touches the risky path.

client_active, client_waiting
server_active, server_idle
maxwait, avg_wait_time
authentication failures
application retries and 5xx responses

PgBouncer's administrative statistics and your existing metrics system should tell the same story. If they do not, stop expanding the rollout until you know whether the disagreement is monitoring lag or actual behavior.

Do Not Skip the Non-Existent Database Case

The published bypass condition includes a connection attempt to a non-existent database. A safe test environment should include a negative test for the database names your routing layer can receive.

Try a known-invalid alias with a low-privilege test identity. Confirm that the request fails as expected and does not result in a connection to a default or privileged backend. Do not reproduce the published exploit mechanics against a production endpoint. The goal is to prove that ordinary invalid input stays ordinary invalid input after the patch.

If applications construct database aliases dynamically, treat that as a design review item. The pooler should have an explicit allowlist or a controlled mapping, and application code should not be able to turn a user-controlled value into a database target.

Roll Out One Failure Domain at a Time

Patch a canary node first when you have more than one. This gives you a real production signal without making the full fleet your test environment.

Define Stop Conditions Before Starting

Write down what causes a rollback or pause. Useful examples include a sustained increase in authentication failures, inability to connect through a critical alias, client wait queues that do not recover, unexpected backend connection counts, or a regression in error rate after the node returns to service.

The point is not to make the operator afraid of every metric movement. It is to avoid arguing about thresholds while customers are waiting. A clear condition lets the change owner pause the rollout without needing permission to notice a problem.

Keep the Previous Artifact Available

Your rollback plan should name the exact previous package version or image digest, configuration revision, and command sequence. It should also state the consequence: a rollback restores availability behavior, but it reintroduces the security exposure until the team has a corrected plan.

That is why validation needs to be fast and concrete. If you cannot distinguish a false alarm from a real incompatibility, the team is forced to choose between two bad states under pressure.

Make the Change Observable From the Client Side

Pooler health can look acceptable while a small class of clients is failing. A blue or green load-balancer target, a running systemd service, and a successful administrative connection only show that the component exists. They do not prove that every application path can authenticate, borrow a connection, complete work, and release it correctly.

Choose a Small Set of Synthetic Transactions

Build a synthetic probe around the least privileged role that can exercise the real route. It should connect through the same hostname and TLS path the application uses, perform a simple read or write in a controlled test namespace, and record the outcome and elapsed time.

Keep it small enough to run during a rollout without adding load. A probe is not a load test and should not impersonate a customer. It answers a narrower question: can a known identity complete a known transaction through this pool after the change?

psql "$DATABASE_URL" \
  --set=ON_ERROR_STOP=1 \
  --command='SELECT current_user, current_database(), now();'

Run the same probe through the canary node where routing permits it, then through the ordinary service address after the node returns to rotation. Pair it with an intentionally invalid credential or alias. A real authentication boundary needs success and failure tests.

Correlate Logs Without Logging Secrets

Give the change a short identifier and write it in the operational timeline, deployment annotation, and dashboard bookmark. That makes it easier to line up an authentication spike with a restart or an upstream application deploy.

Do not add passwords, full connection strings, SCRAM verifier material, or raw application payloads to the logs in the name of troubleshooting. If a connection needs correlation, use a safe request ID, a hashed identifier approved by the security team, or ordinary database log fields already governed by retention policy.

Use a Baseline With a Time Window

Connection pools naturally move as traffic changes. Compare the first ten minutes after a node returns with a similar weekday and traffic window where possible. Ask whether waits, authentication failures, error rates, or backend connections have changed in a way the application owner can explain.

A single elevated number does not always mean the patch is at fault. A new peak with no explanation is still a reason to pause. The change owner should be able to say which metric they watched, what it normally does, and why the current value is acceptable.

Check the Boundaries Between PgBouncer and PostgreSQL

PgBouncer sits between clients and database servers, so an apparently small pooler change can reveal an old mismatch in roles, TLS, timeouts, routing, or connection limits. Use the rollout to check the contract on each side.

Confirm Backend Capacity

The pooler protects PostgreSQL from connection storms only when its limits reflect the database capacity. Before returning a fully patched fleet to service, confirm that server connections are not growing beyond the expected per-pool limits and that application queues are not simply moving from PgBouncer into PostgreSQL.

SELECT datname, usename, state, count(*)
FROM pg_stat_activity
GROUP BY datname, usename, state
ORDER BY datname, usename, state;

Read this alongside the pooler's client and server counts. A sudden jump in idle backend sessions after a restart can be a configuration or routing clue. A steady count with growing client waits may point to workload pressure or a transaction that is not releasing a connection.

Exercise TLS and Certificate Rotation Paths

If PgBouncer terminates or initiates TLS, test the normal certificate path while the patched binary is running. Confirm the expected certificate authority, hostname verification mode, client certificate behavior where applicable, and reload or restart process for future certificate rotations.

This does not mean changing certificates during a security patch. It means making sure the team knows that the next urgent maintenance task will use the same operating boundary and that its validation does not rely on a lucky manual command.

Check Timeouts and Retries as a Pair

An application retry loop can make an authentication or connection failure look like high load. A pool timeout can make a slow backend query look like a pooler outage. During the canary, look at the client-side retry count and timeout classification together with the pooler's own counters.

If the two systems disagree, trace one failed request from application log to pooler log to database log using the safe identifiers already available. Do not respond by raising every timeout. That can hide the symptom while making the next failure slower and harder to contain.

Turn the Upgrade Into a Repeatable Security Response

The practical value of this release is not a more elaborate ceremony around one package. It is a small repeatable path for components that sit on authentication and availability boundaries.

Keep an Asset and Ownership Record

For every production PgBouncer deployment, retain the service owner, database owner, repository or configuration source, deployment artifact, version query, and recovery contact. A future advisory should not begin with a week of asking where the pooler lives.

An ownership record also prevents the common handoff problem: application teams assume the platform team owns the pooler, platform teams assume the database team owns authentication, and nobody owns the exact setting that decides how a connection is admitted.

Separate Urgent Work From Unrelated Cleanup

Security patches often expose good ideas: pin the image, reduce privileged roles, add a test database alias, improve dashboards, or redesign a secret path. Record those ideas. Do not attach them all to the urgent patch unless they are required for the fix.

Small changes are easier to validate, roll back, and explain. The post-patch backlog is where broader hardening belongs, with its own owner and deadline.

Close the Change With Evidence

The final change record should include the fixed version, affected nodes, rollout time, validation results, metrics observed, security review outcome, and any follow-up work. It should be detailed enough for the next on-call engineer to understand the decision without searching chat history.

That record is also how a quick patch remains defensible. It shows that the team removed the vulnerable code and checked that the system behaved as intended afterward.

Update the Runbook After the Last Node

The release provides a useful prompt to make the next response less improvised. Add PgBouncer to the inventory of authentication-adjacent components, record who owns the pooler configuration, and document how to retrieve a version and drain a node.

Also make the test plan reusable. A good runbook has a safe connection test, a rejected-login test, a traffic-drain procedure, a metric dashboard link, and a rollback reference. It does not need to contain real secrets or a fragile command copied from one host.

What to Keep Monitoring

Keep an eye on authentication failures, connection errors, pool waits, backend saturation, application latency, retry volume, and error rates after the full rollout. Watch long enough to include a normal traffic peak if the change window permits.

The security fix is the reason to move now. The lasting value comes from treating the pooler as production infrastructure with an owner, a test path, and a recovery path.

A Compact Change Checklist

Use this list as a final handoff rather than as a substitute for the details above. Every line should have an owner and a recorded result.

Before the First Node

  1. Confirm the affected version, artifact digest, configuration revision, and node inventory.
  2. Preserve the logs and telemetry needed for the security review.
  3. Identify SCRAM pools, privileged routes, authentication sources, and database aliases.
  4. Prepare a least-privilege synthetic transaction and an expected-failure test.
  5. Name the validation window, pause conditions, rollback artifact, and change owner.

At the Canary

  1. Remove one node from new traffic and verify capacity remains healthy.
  2. Deploy PgBouncer 1.26.1 with the tested configuration.
  3. Run valid and invalid authentication checks through the intended route.
  4. Check client waits, backend connection counts, authentication errors, latency, and retries.
  5. Exercise an invalid database alias in a safe environment and confirm it fails correctly.
  6. Return the node to service only when the application owner and change owner can explain the results.

After the Fleet

  1. Confirm the vulnerable version is no longer serving traffic.
  2. Review the short post-change window with the database and security owners.
  3. Record the actual duration, anomalies, credential decision, and follow-up work.
  4. Update the runbook while the commands, dashboards, and edge cases are still fresh.

The checklist is deliberately operational. A security advisory describes a flaw; production work is the sequence that removes it without creating another one.

Sources and Further Reading

Frequently Asked Questions

Is PgBouncer 1.26.1 only relevant to public databases?

No. The reported denial-of-service flaws are triggerable by unauthenticated clients, and the authentication bypass concerns access to a privileged boundary. Internal reachability reduces some exposure but does not remove the need to patch and review the network path.

Should we combine this with a PostgreSQL major upgrade?

No. Patch the pooler as a focused security change. Plan a PostgreSQL major upgrade with its own rehearsals, compatibility checks, and rollback decision.

What is the safest success criterion?

The patched version is running on every intended node, normal application traffic succeeds, intentionally invalid authentication and database targets fail as expected, metrics stay within agreed bounds, and the old vulnerable artifact is no longer serving traffic.


FAQs

What does PgBouncer 1.26.1 fix?

PgBouncer 1.26.1 fixes three CVEs. One can let a client that knows one SCRAM user's password authenticate as another SCRAM user under a specific startup-message condition. Two others can cause unauthenticated denial of service through infinite loops.

Should we rotate every PostgreSQL password after upgrading PgBouncer?

The release notes describe a specific authentication bypass, not a disclosure of all stored credentials. Prioritize the patch, preserve relevant logs, review the affected SCRAM exposure path, and decide on targeted credential rotation with your security team.

How can we test PgBouncer after the upgrade?

Run known-good application traffic through each pool, test expected and rejected SCRAM logins, exercise a short transaction workload, check pool statistics and backend connection counts, and validate that your rollback path is still usable.

Can PgBouncer 1.26.1 change search_path handling?

Yes. The release makes ignore_startup_parameters take precedence over tracked parameters. If you use ignore_startup_parameters = search_path, review the stated restoration of the 1.25 behavior in a non-production environment.

Do we need downtime for a PgBouncer upgrade?

The safest procedure is a controlled drain and restart of each PgBouncer instance. The precise interruption depends on your topology, pooling mode, load balancer behavior, and whether connections can move to healthy peers.

What should we monitor after a PgBouncer patch?

Monitor authentication failures, client and server active or waiting counts, connection errors, latency, retries, backend saturation, and application error rates. Compare the results with a pre-change baseline.

🚀

Work with us

Let's build something together

We build fast, modern websites and applications using Next.js, React, WordPress, Rust, and more. If you have a project in mind or just want to talk through an idea, we'd love to hear from you.

Related Articles


Live Chat