On a partitioned table, logical decoding emits changes for the leaf partition.
Its REPLICA IDENTITY is the one that counts — the parent’s is never read. And
ALTER on the parent doesn’t propagate:
CREATE TABLE t (id bigint, created_at timestamp, PRIMARY KEY (id, created_at))
PARTITION BY RANGE (created_at);
CREATE TABLE t_p1 PARTITION OF t FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');
ALTER TABLE t REPLICA IDENTITY FULL;
-- t -> f
-- t_p1 -> d existing partition: no cascade
CREATE TABLE t_p2 PARTITION OF t FOR VALUES FROM ('2027-01-01') TO ('2028-01-01');
-- t_p2 -> d new partition: not inherited
A partition is born DEFAULT and stays there. For replication, ALTER on the
parent is a silent no-op.
This bites CDC. AWS DMS warns that it doesn’t support REPLICA IDENTITY FULL when
the endpoint uses the pglogical plugin — and sure enough, UPDATEs never reach
the target. If the leaves are FULL, looking at the parent gives nothing away: its
value is independent of what decoding actually sees.
The fix is one line per partition:
ALTER TABLE t_p1 REPLICA IDENTITY DEFAULT; -- now uses the PK
ALTER TABLE t_p2 REPLICA IDENTITY DEFAULT;
Catalog-only: no rewrite, milliseconds, regardless of table size.
Check afterwards — always on the leaves, never the parent:
SELECT c.relname,
CASE c.relreplident WHEN 'd' THEN 'DEFAULT' WHEN 'f' THEN 'FULL'
WHEN 'n' THEN 'NOTHING' WHEN 'i' THEN 'INDEX' END AS ri
FROM pg_inherits i
JOIN pg_class c ON c.oid = i.inhrelid
WHERE i.inhparent = 't'::regclass
ORDER BY c.relname;
DEFAULT uses the primary key — and since the partition key must be part of the PK,
it’s already there.