subscriptionStats

Return the runtime state of every logical replication subscription in this database: each worker with its type, pid, the relation it is syncing and how long since it last heard from the publisher; per-table sync state, with the tables that are not yet ready listed individually…

read-onlyany connectionsweeps instancesweeps replication groupsweeps group

Synopsis

subscriptionStats()

Description

Return the runtime state of every logical replication subscription in this database: each worker with its type, pid, the relation it is syncing and how long since it last heard from the publisher; per-table sync state, with the tables that are not yet ready listed individually; and the apply and sync error counters plus the per-conflict-type counters. Answers whether a subscriber is keeping up and, if not, whether it is stuck syncing a table or failing to apply.

Reports no byte lag, and this is definitional rather than a limitation to be revisited: received_lsn is the last WAL location RECEIVED and latest_end_lsn the last one REPORTED BACK to the publisher's WAL sender, so neither references the publisher's WAL position and no difference between them can express backlog. What it does express is feedback latency, bounded by the status-report interval rather than by lag -- which is why it reads zero with a subscriber far behind.

Note also that received_lsn, latest_end_lsn and both last_msg_* timestamps are null for a parallel apply worker, so such a row is not broken. For lag in bytes call replicationSlots on the PUBLISHER and read retained_wal_bytes. When a table is still copying, its worker pid is a real backend pid: pass it to progressStats to get the byte count of that exact copy. Complements listSubscriptions, which is the structural half.

Parameters

None of its own.

Also accepts connection, instance, replication_group, group, role, described once under arguments every tool takes.

Output

Keyed by subscription name; each value is its worker state, table sync progress and error counters. An absent extension or a missing grant is reported as {error, hint} in place of the map.

Scope

The counters here are each server's own, so members of a replication group legitimately disagree and the answer is their sum, not the primary's copy. Dead tuples and the last vacuum and analyze times describe work that only happens on a primary; on a replica they are noise, not a second opinion.

Example mocked data

Request

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "subscriptionStats",
    "arguments": {}
  }
}

Result

{
  "from_erp": {
    "apply_error_count": 0,
    "sync_error_count": 1,
    "stats_reset": null,
    "workers": [
      {
        "worker_type": "apply",
        "pid": 51102,
        "leader_pid": null,
        "relation": null,
        "msg_age_s": 0.4,
        "latest_end_time": "2026-09-15T10:02:11Z"
      }
    ],
    "tables": {
      "total": 3,
      "ready": 3,
      "not_ready": []
    }
  }
}

Invented values on a fictional shop database, shaped by and checked against this tool's output schema. Real output is returned as structuredContent to clients that negotiate MCP 2025-06-18 or later.

See also

replicationStats, listForeignTables, listForeignServers, listPublications, listSubscriptions, replicationSlots