Recommended way to configure max_prepared_transactions in Postgres on Kubernetes
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
max_prepared_transactions is one of those PostgreSQL settings you should leave alone unless you know you need two-phase commit. On Kubernetes, the right way to configure it is not a one-off shell edit inside a pod, but a durable server-start configuration managed by your chart, operator, or mounted config file.
First Decide Whether You Need It At All
Prepared transactions are used for two-phase commit through PREPARE TRANSACTION. Many Postgres deployments never use that feature, and PostgreSQL defaults max_prepared_transactions to 0, which disables it. That is usually the correct setting.
Keep it at 0 unless your application stack explicitly uses prepared transactions through:
- XA or JTA-style transaction coordination
- a distributed transaction manager
- application code that issues
PREPARE TRANSACTION
If you are not using those patterns, enabling prepared transactions only increases the risk of orphaned prepared work and operational confusion.
If You Do Need It, Size It Intentionally
If your workload genuinely uses prepared transactions, PostgreSQL documentation recommends sizing max_prepared_transactions at least as high as max_connections so each session can have one prepared transaction pending if necessary.
This setting:
- defaults to
0 - is a server-start parameter
- must be the same or higher on standby servers than on the primary
That means a normal ALTER SYSTEM habit or a psql session change is not the right mental model here. Plan a restart and make the value part of the declared deployment configuration.
Configure It Through the Kubernetes Source of Truth
The exact mechanism depends on how Postgres is deployed, but the rule is the same: change the configuration in the thing that creates the pod.
For a plain StatefulSet with a mounted config file, that can look like this:
And in the pod spec:
If you are using Helm, Patroni, Crunchy, CloudNativePG, or another operator, set the parameter in that product’s values or custom resource instead. Do not patch the running container manually, because the next restart will discard the change.
Verify Both the Setting and Its Usage
After rollout, verify the effective value:
Also inspect whether prepared transactions are actually accumulating:
That second query matters operationally. A nonzero setting is only safe if your application reliably commits or rolls back prepared transactions. Otherwise, locks and resources can remain stuck until an operator intervenes.
A Practical Recommendation
For most Kubernetes teams, the best recommendation is:
- leave
max_prepared_transactions = 0 - only enable it when the application architecture truly requires two-phase commit
- manage it in versioned deployment config
- roll it out with a planned restart
- monitor
pg_prepared_xacts
That approach is boring, and boring is exactly what you want in database operations.
Common Pitfalls
The biggest pitfall is enabling the setting because a framework mentions "transactions" without confirming it uses prepared transactions specifically. Ordinary Postgres transactions do not require this parameter.
Another mistake is changing the file inside a running pod. In Kubernetes, the durable configuration lives in manifests, chart values, or operator resources, not in interactive container edits.
Teams also forget replicas. Standby nodes must have the same or higher value than the primary, or read queries on the standby can fail.
Finally, do not enable prepared transactions without a cleanup story. An application bug that leaves prepared transactions open can block work long after the original request path is gone.
Summary
- Leave
max_prepared_transactionsat0unless you truly use two-phase commit. - If enabled, size it deliberately, often at least as high as
max_connections. - Configure it through your Helm chart, operator, or mounted config, not by editing pods.
- Restart PostgreSQL to apply the change because it is a server-start parameter.
- Monitor
pg_prepared_xactsso prepared transactions do not accumulate silently.
Related reading
- Recover a Kubernetes Cluster
- Redirect http port to nodePort
- Redirect non www to www using ALB Ingress Controller
- Redis master/slave setup on Kubernetes throwing error BRPOPLPUSH ReplyError MOVED 2651
- recursive query for adjacency list to preorder tree traversal in SQL?
- redis-cli connection to Amazon ElastiCache Redis cluster hangs up
- Reconnecting to Kafka with node-rdkafka is slow & inconsistent
- Reconstructing the list of items from a space optimized 0/1 knapsack implementation

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.