Cloud Parts

Patroni

A Python agent beside each Postgres server that elects one primary through etcd, Consul, ZooKeeper or Kubernetes, and fails over when it dies.

Type
Open source
Made by
Patroni community (started at Zalando)
License
MIT
Facts checked
6 October 2026

What it is

Patroni runs as one agent process next to every PostgreSQL server in a cluster, usually three. The agents never vote among themselves. They share a distributed configuration store (DCS): etcd, Consul, ZooKeeper, or the Kubernetes API itself. Every loop_wait seconds (10 by default) each agent runs an HA cycle. The primary renews a leader key in the DCS that carries a lease (ttl, 30 seconds by default), and the replicas stream WAL from whoever holds it. If the primary stops renewing, the lease expires and a leader race starts: each healthy replica checks that it is the best candidate (not further behind than maximum_lag_on_failover, no other member holding more WAL), then tries to create the key atomically. The one that succeeds promotes its Postgres to primary; the others follow it. A primary that can no longer update the key demotes itself to read-only, so two primaries never accept writes at once.

Patroni also manages Postgres itself: it bootstraps the first node, clones replicas, rejoins a failed primary as a replica with pg_rewind, and keeps cluster-wide settings in the DCS, edited with patronictl edit-config. Each agent serves a REST API on port 8008, where GET /primary returns 200 only on the current leader, so HAProxy, Envoy or a cloud load balancer can send clients to the right node; on Kubernetes, Patroni labels the leader pod instead. It is free and MIT-licensed, supports PostgreSQL 9.3 to 18, and sits inside Zalando’s Spilo images and Postgres Operator. Datadog’s 2025 move off cloud-managed Postgres runs it on Kubernetes with ZooKeeper as the DCS and WAL-G for backups.

Why teams pick it

  • Split-brain defences in layers: a leased leader key, self-demotion when the lease can’t be renewed, an optional Linux watchdog that resets a stuck node, and a failsafe mode for DCS outages
  • Runs anywhere: VMs, bare metal, or Kubernetes, where the API server can hold the leader key so no separate etcd is needed
  • Manages the whole cluster life cycle: bootstrap, new replicas, switchover, rejoining old primaries, and configuration pushed to every node
  • Asynchronous, synchronous or quorum-commit replication, with maximum_lag_on_failover and failover_priority to control who may be promoted
  • Plain MIT licence and wide use: most Postgres operators for Kubernetes other than CloudNativePG build on Patroni or a similar tool

Watch out for

  • Outside Kubernetes you must run and monitor a DCS cluster too; if it loses quorum, Patroni demotes the primary to read-only unless failsafe_mode is on and every replica can be reached
  • Asynchronous replication is the default, so a failover can lose up to maximum_lag_on_failover bytes plus the writes of the last ttl seconds; synchronous modes avoid that at the cost of write latency
  • It doesn’t route or pool connections: you add HAProxy, Envoy, a Kubernetes Service or a load balancer that checks the REST API, plus PgBouncer if needed
  • No backups of its own; pair it with WAL-G, pgBackRest or Barman for archives and point-in-time recovery
  • You own upgrades and testing of Postgres, Patroni and the DCS together; Patroni 4.0 renamed master to primary in the API, labels and DCS, a breaking change for scripts

Alternatives

What all relational databases have in common →
Alibaba Cloud PolarDBCommercialAlibaba Cloud’s cloud-native relational databases: MySQL- and PostgreSQL-compatible clusters whose compute nodes share one copy of the data on distributed storage, plus PolarDB-X, a distributed MySQL-compatible edition.CedarDBCommercialA PostgreSQL-compatible database rebuilt from scratch at TU Munich, running transactions and analytics on one copy of the data on a single server.Cloudflare D1CommercialCloudflare’s serverless SQL database that speaks SQLite, runs each database inside a Durable Object, and bills by rows read and written rather than by the hour.CloudNativePGOpen sourceA Kubernetes operator that runs highly available PostgreSQL with no Patroni and no StatefulSets: the Kubernetes API itself holds the cluster’s state.CockroachDBCommercialA distributed SQL database that speaks the PostgreSQL wire protocol, replicates every slice of data with Raft and keeps transactions serializable across nodes and regions.MySQLOpen sourceThe long-standing open-source SQL database behind much of the web, built on the InnoDB engine.NeonCommercialServerless Postgres that keeps data in a shared storage layer, so compute can scale to zero and a branch of the database is a pointer, not a copy.Percona OperatorsOpen sourceFour free Kubernetes operators from Percona that run its builds of MySQL, PostgreSQL and MongoDB, each using the engine’s own replication and backup tools.PGO (Crunchy Postgres for Kubernetes)Open sourceCrunchy Data’s Postgres operator: Patroni in every pod for failover, pgBackRest for backups, and a declarative `PostgresCluster` resource on top.PlanetScaleCommercialManaged MySQL on Vitess and managed Postgres, with schema changes shipped through branches and deploy requests.PostgreSQLOpen sourceThe open-source relational database that most new projects start on, extensible enough to grow into many niches.ScramDBCommercialA brand-new, closed-source database that speaks the PostgreSQL protocol and promises transactions, analytics and vector search on one copy of the data; first builds shipped in summer 2026.SQLiteOpen sourceA complete SQL database in a library and a single file, with no server to run.TursoOpen sourceA from-scratch Rust rewrite of SQLite with concurrent writes, plus libSQL (an open-contribution SQLite fork) and Turso Cloud, which hosts many small databases on S3.VitessOpen sourceA proxy layer, born at YouTube, that shards MySQL across many servers while the app still sees one database.

How it fits with other technologies

patroni.yml for the first of three nodes; the others change only name and addresses · yaml

scope: orders            # cluster name; DCS keys live under /service/orders/
name: pg-1

restapi:
  listen: 0.0.0.0:8008
  connect_address: 10.0.1.11:8008   # load balancers poll GET /primary here

etcd3:
  hosts: 10.0.0.5:2379,10.0.0.6:2379,10.0.0.7:2379

bootstrap:
  dcs:                   # written to the DCS once; later: patronictl edit-config
    ttl: 30              # leader lease in seconds
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576   # replicas over 1 MB behind are not promoted
    synchronous_mode: false
    postgresql:
      use_pg_rewind: true
      parameters:
        archive_mode: "on"
        archive_command: "wal-g wal-push %p"
  initdb:
  - encoding: UTF8
  - data-checksums

postgresql:
  listen: 0.0.0.0:5432
  connect_address: 10.0.1.11:5432
  data_dir: /var/lib/postgresql/18/main
  bin_dir: /usr/lib/postgresql/18/bin
  authentication:
    superuser:   { username: postgres, password: change-me }
    replication: { username: replicator, password: change-me }

watchdog:
  mode: automatic        # use /dev/watchdog if present

# patroni /etc/patroni.yml        start the agent on each node
# patronictl -c /etc/patroni.yml list
# patronictl -c /etc/patroni.yml switchover --candidate pg-2

Patroni or another way to fail over Postgres?#

All of these promote a streaming replica when the primary dies. They differ in who makes the decision and what else you have to run.

Patronirepmgrpg_auto_failoverCloudNativePGRDS Multi-AZ
Who decidesEach node’s agent, by racing for a leader key in a DCSThe nodes, by talking to each otherA central monitor that instructs a keeper on each nodeThe operator, keeping cluster state in the Kubernetes APIAWS
Extra piecesA DCS (three or more etcd, Consul or ZooKeeper nodes) unless on Kubernetes; a proxy or load balancerNone beyond the Postgres nodesOne monitor nodeA Kubernetes clusterNone
Runs onVMs, bare metal, KubernetesVMs, bare metalVMs, bare metalKubernetes onlyAWS only
LicenceMITGPL v3 (from EDB)PostgreSQL License (from Microsoft)Apache 2.0Proprietary, paid per instance
  • pg_auto_failover keeps replication running if the monitor fails, but can’t react to another failure until it is back.
  • RDS Multi-AZ (single standby) keeps a synchronous standby in another zone that can’t serve reads; AWS says failovers typically take 60 to 120 seconds.

See it in a real stack

No architecture uses Patroni yet. Drop it into the playground and wire it up yourself.Open playground →

Worth exploring

Slides· September 2025How and Why Datadog moved from cloud-managed to self-managed PostgresNick Canzoneri, Datadog, at PGConf NYC 2025Slides from a talk on why a company running hundreds of Postgres clusters across several clouds left managed services for its own Postgres platform on Kubernetes, how it moved a whole region, and what got better and worse. The stack is Patroni (with ZooKeeper for leader election), WAL-G backups, a Helm chart rather than an operator, and Temporal workflows for automation. Useful before you weigh RDS-style convenience against running Postgres yourself.
All resources →
Where it came from2015–2025

PostgreSQL has had built-in streaming replication since 2010, but nothing in it decides when a replica should take over. In January 2015 Compose, which ran Postgres as a service, described Governor: a small Python program on each node that used etcd as the “repository of truth”. Whichever node set a leader key, with a 30-second time-to-live, was the primary and had to keep refreshing it; when the key vanished, the others raced to set it.

Zalando’s database team forked Governor in mid-2015 as Patroni, added more stores and much more automation, and presented it at FOSDEM PGDay in January 2016. Version 1.0 followed in July 2016 with cluster-wide configuration kept in the DCS. Compose later deprecated Governor and moved to Patroni itself.

Patroni became the usual way to run highly available Postgres outside managed services, and the base of Zalando’s Spilo images and Kubernetes operator. The project now lives in its own GitHub organisation, with Zalando credited in the licence and in its old name.

Why it’s built this way

An external store as the single source of truth
Tools such as repmgr let the nodes talk among themselves. Patroni only acts on what the DCS says, which costs an extra cluster but makes split-brain less likely, because the DCS has its own quorum.
A leader key with a lease instead of a vote
Governor’s idea, kept by Patroni: holding the key is what makes a node primary, and a node that can’t renew it demotes itself before the lease runs out.
A template that manages Postgres, not just failover
Bootstrapping, cloning replicas, rewinding a failed primary and pushing configuration all follow from the same state in the DCS, so the project calls itself a template for HA solutions.
Pluggable stores, including Kubernetes
Different teams already ran etcd, Consul or ZooKeeper; on Kubernetes, keeping the leader key in Endpoints or ConfigMaps means no extra etcd deployment.

Timeline

  1. 2015

    Compose describes Governor in January; Zalando forks it as Patroni in July

  2. 2016

    FOSDEM PGDay talk; version 1.0 adds dynamic cluster-wide configuration

  3. 2020

    2.0 adds etcd v3 support and an experimental built-in Raft store

  4. 2023

    3.0 adds Citus support and DCS failsafe mode; Raft deprecated

  5. 2024

    4.0 adds quorum-based failover and drops the term “master”

  6. 2025

    4.1 released in September

Sources24 · facts checked 6 October 2026

Improve this page on GitHub