> ## Documentation Index
> Fetch the complete documentation index at: https://powersync-docs-postgres-message-limit-recovery.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Postgres Maintenance

> Manage Postgres replication slots and WAL lag for reliable PowerSync replication.

## Logical Replication Slots

Postgres logical replication slots are used to keep track of [replication](/architecture/powersync-service#replication-from-the-source-database) progress (recorded as a [LSN](https://www.postgresql.org/docs/current/datatype-pg-lsn.html)).

Every time a new version of [Sync Streams or Sync Rules](/sync/overview) is deployed, PowerSync creates a new replication slot. Once the new version is fully processed, PowerSync switches to use the new slot and deletes the old one. The Service logs these steps and, during a snapshot, how much WAL budget remains. See [Postgres Replication Slots and WAL Budget](/debugging/log-reference#postgres-replication-slots-and-wal-budget) in the Log Reference.

The replication slots can be viewed using this query:

```sql theme={null}
select slot_name, confirmed_flush_lsn, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) as lag from pg_replication_slots;
```

Example output:

| slot\_name             | confirmed\_flush\_lsn | active | lag      |
| ---------------------- | --------------------- | ------ | -------- |
| powersync\_1\_c3c8cf21 | 0/70D8240             | 1      | 56 bytes |
| powersync\_2\_e62d7e0f | 0/70D8240             | 1      | 56 bytes |

In some cases, a replication slot may remain without being used. In this case, the slot prevents Postgres from deleting older WAL entries. For example, this happens when a PowerSync instance has been deprovisioned.

Keeping unused slots alive prevents WAL cleanup, which can lead to excessive disk usage. If a slot is no longer needed, it should be dropped.

Inactive slots can be dropped using:

```bash theme={null}
select slot_name, pg_drop_replication_slot(slot_name) from pg_replication_slots where active = false;
```

Postgres prevents active slots from being dropped. If an active slot is somehow dropped while a PowerSync instance is disconnected, PowerSync will automatically recreate the slot when it reconnects and restart replication.

### Recovering from an Invalidated Slot

A replication slot becomes invalidated when its `wal_status` is `lost`. This happens when the WAL data needed by the slot has been removed, typically because the replication lag exceeded `max_slot_wal_keep_size`.

When this occurs, you will see an error such as:

> Replication slot powersync\_1\_xxxx was invalidated (reason: wal\_removed). Increase max\_slot\_wal\_keep\_size on the source database and delete the existing slot to recover.

To recover:

1. Increase `max_slot_wal_keep_size` on the source Postgres database to prevent re-occurrence. See [Managing and Monitoring Replication Lag](/maintenance-ops/production-readiness-guide#managing-and-monitoring-replication-lag) for sizing guidance.

2. Drop the invalidated slot:

```sql theme={null}
SELECT pg_drop_replication_slot('powersync_1_xxxx');
```

Replace `powersync_1_xxxx` with the actual slot name from the error message.

3. Restart the PowerSync Service. It will create a new replication slot and begin replication from scratch.

<Note>If the slot was invalidated during the initial snapshot (before it completed), the PowerSync Service will not automatically retry. You must drop the invalidated slot manually before the service can recover.</Note>

If the invalidation reason is `idle_timeout` (Postgres 18+), the slot was invalidated due to inactivity. In this case, increase `idle_replication_slot_timeout` on the source database instead.

### Maximum Replication Slots

Postgres is configured with a maximum number of replication slots per server. Each PowerSync instance uses one replication slot for replication and an additional one while deploying a new Sync Streams or Sync Rules version. The maximum number of PowerSync instances you can connect to one Postgres server is equal to the maximum number of replication slots, minus one.

If other clients are also using replication slots, this number is reduced further.

To configure the maximum number of slots, set `max_replication_slots` (though not all hosting providers expose this setting). Check the current value using:

```sql theme={null}
select current_setting('max_replication_slots')
```

If this number is exceeded, you'll see an error such as "all replication slots are in use".

## Oversized Replication Messages

Postgres replication currently has a **50 MiB receive buffer limit**. A message that cannot fit can stall replication, with `postgres sent too big message` in the Replicator logs.

The limit applies to every table in the publication, even those not referenced by Sync Streams. Publish only required tables and keep source rows within the separate [15 MiB row/document limit](/resources/performance-and-limits#limits).

<Note>With `REPLICA IDENTITY FULL`, a message can include both previous and new row values, which doubles the size of a single row.</Note>

### Recovery

This involves removal of oversized rows from replication and a potential reprocessing:

<Steps>
  <Step title="Identify Source">
    Review writes across all published tables for oversized rows. The time of the error's first occurrence can help identify the source table.
  </Step>

  <Step title="Correct the Source">
    If the affected table is part of the PowerSync publication but not used by any Sync Streams, then remove the table from the publication and redeploy the service, and skip to step 4.

    Otherwise, reduce the size of the oversized row or delete it from the source database and move on to step 3.
  </Step>

  <Step title="Start a New Snapshot">
    Start [full reprocessing](/maintenance-ops/compacting-buckets#defragmenting-strategies) for each affected instance. This creates a new replication slot and snapshots the current source data. Deleting a row alone does not erase its earlier WAL entries.

    <Tabs>
      <Tab title="PowerSync Cloud">
        In the PowerSync Dashboard, open **Settings**, then select **Defragment** in the **Compact operation history** section.
      </Tab>

      <Tab title="Self-Hosted">
        Set `POWERSYNC_URL` to your Service URL. Set `PS_API_TOKEN` to an admin token configured under [`api.tokens`](/configuration/powersync-service/self-hosted-instances#api).

        ```bash theme={null}
        curl "${POWERSYNC_URL}/api/admin/v1/reprocess" \
          -H "Authorization: Bearer ${PS_API_TOKEN}" \
          --json '{}'
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Verify Recovery">
    If you reprocessed, confirm in your logs that the new replication stream is active. Check that replication lag decreases and clients receive new source updates.
  </Step>
</Steps>
