Skip to content

Lack of support for cascading replication topology in pgpool streaming replication checks #159

@rotomasz

Description

@rotomasz

I am running pgpool2 with PostgreSQL streaming replication and a larger topology:

  • pgpool2 version: 4.7.1
  • PostgreSQL version: 17.9
  • Backend topology: 1 primary + 11 standbys
  • Backend mode: streaming replication

I use pgpool2 exclusively for load balancing. I would like to configure cascading replication for 5 of the standbys, as described in the PostgreSQL documentation: https://www.postgresql.org/docs/current/warm-standby.html#CASCADING-REPLICATION

Example topology

host1   primary

host2   standby, replicates directly from host1
host3   standby, replicates directly from host1
host4   standby, replicates directly from host1
host5   standby, replicates directly from host1
host6   standby, replicates directly from host1
host7   standby, replicates directly from host1

host8   cascading standby, replicates from host7
host9   cascading standby, replicates from host7
host10  cascading standby, replicates from host7
host11  cascading standby, replicates from host7
host12  cascading standby, replicates from host7

So the intended replication tree is:

host1
├── host2
├── host3
├── host4
├── host5
├── host6
└── host7
    ├── host8
    ├── host9
    ├── host10
    ├── host11
    └── host12

Issue
After enabling cascading replication, pgpool2 repeatedly logs messages from sr_check_worker, and some standby nodes no longer show values in the replication_state and replication_sync_state columns.

Actual behavior

After configuring 5 standbys to replicate from another standby, pgpool.log repeatedly contains entries like this:

2026-04-29 09:12:52.393: sr_check_worker pid 127667: LOG:  verify_backend_node_status: primary 6 does not connect to standby 1
2026-04-29 09:12:52.393: sr_check_worker pid 127667: DETAIL:  pgpool.conf backend: (host="host7" port=5432) does not match PostgreSQL primary_conninfo: (host="host1" port=5432)
2026-04-29 09:12:52.394: sr_check_worker pid 127667: LOG:  verify_backend_node_status: primary 6 does not connect to standby 2
2026-04-29 09:12:52.394: DETAIL:  pgpool.conf backend: (host="host7" port=5432) does not match PostgreSQL primary_conninfo: (host="host1" port=5432)
2026-04-29 09:12:52.395: sr_check_worker pid 127667: LOG:  verify_backend_node_status: primary 6 does not connect to standby 3
2026-04-29 09:12:52.395: DETAIL:  pgpool.conf backend: (host="host7" port=5432) does not match PostgreSQL primary_conninfo: (host="host1" port=5432)
2026-04-29 09:12:52.396: sr_check_worker pid 127667: LOG:  verify_backend_node_status: primary 6 does not connect to standby 4
2026-04-29 09:12:52.396: DETAIL:  pgpool.conf backend: (host="host7" port=5432) does not match PostgreSQL primary_conninfo: (host="host1" port=5432)
2026-04-29 09:12:52.398: sr_check_worker pid 127667: LOG:  verify_backend_node_status: primary 6 does not connect to standby 5
2026-04-29 09:12:52.398: DETAIL:  pgpool.conf backend: (host="host7" port=5432) does not match PostgreSQL primary_conninfo: (host="host1" port=5432)
2026-04-29 09:12:52.484: sr_check_worker pid 127667: LOG:  verify_backend_node_status: primary 6 owns only 6 standbys out of 11

It looks like pgpool2 is checking whether every standby's primary_conninfo points to the same backend, and treats a cascading topology as incorrect because some standbys intentionally point to another standby.

Example of SHOW POOL NODES;

 node_id | hostname | port | status | pg_status | lb_weight |  role   | pg_role | select_cnt | load_balance_node | replication_delay | replication_state | replication_sync_state | last_status_change
---------+----------+------+--------+-----------+-----------+---------+---------+------------+-------------------+-------------------+-------------------+------------------------+---------------------
 0       | host1    | 5432 | up     | up        | 0.166667  | primary | primary | 428        | false             | 0                 |                   |                        | 2026-04-29 09:20:29
 1       | host2    | 5432 | up     | up        | 0.166667  | standby | standby | 89         | true              | 0.000000 second   | streaming         | sync                   | 2026-04-29 09:20:29
 2       | host3    | 5432 | up     | up        | 0.166667  | standby | standby | 2          | false             | 0.000000 second   | streaming         | potential              | 2026-04-29 09:20:29
 3       | host4    | 5432 | up     | up        | 0.166667  | standby | standby | 87         | false             | 0.000000 second   | streaming         | potential              | 2026-04-29 09:20:29
 4       | host5    | 5432 | up     | up        | 0.166667  | standby | standby | 0          | false             | 0.000000 second   | streaming         | potential              | 2026-04-29 09:20:29
 5       | host6    | 5432 | up     | up        | 0.166667  | standby | standby | 2          | false             | 0.000000 second   | streaming         | potential              | 2026-04-29 09:20:29
 6       | host7    | 5432 | up     | up        | 0.000000  | standby | standby | 0          | false             | 0.000000 second   | streaming         | async                  | 2026-04-29 09:20:29
 7       | host8    | 5432 | up     | up        | 0.000000  | standby | standby | 0          | false             | 0.000000 second   |                   |                        | 2026-04-29 09:20:29
 8       | host9    | 5432 | up     | up        | 0.000000  | standby | standby | 0          | false             | 0.000000 second   |                   |                        | 2026-04-29 09:20:29
 9       | host10   | 5432 | up     | up        | 0.000000  | standby | standby | 0          | false             | 0.000000 second   |                   |                        | 2026-04-29 09:20:29
 10      | host11   | 5432 | up     | up        | 0.000000  | standby | standby | 0          | false             | 0.000000 second   |                   |                        | 2026-04-29 09:20:29
 11      | host12   | 5432 | up     | up        | 0.000000  | standby | standby | 0          | false             | 0.000000 second   |                   |                        | 2026-04-29 09:20:29

For the cascading standbys, the replication_state and replication_sync_state columns are empty.

Expected behavior

  • pgpool2 should support PostgreSQL cascading replication in streaming replication mode.
  • For cascading standbys, pgpool2 should recognize that primary_conninfo may point to an upstream standby rather than the top-level primary.
  • pgpool2 should not repeatedly log warnings/errors for a valid cascading replication topology.
  • The replication_state and replication_sync_state columns should also be populated where pgpool2 can determine the replication status.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions