PG-R15capacityConfidence: 95%Reversibility: manual

Sequence Near Exhaustion

System views: pg_sequences, information_schema.columns

Overview

Postgres SERIAL and BIGSERIAL columns use sequences that increment monotonically. An INTEGER (int4) sequence maxes out at 2,147,483,647 (2.1 billion). A BIGINT (int8) sequence maxes out at 9.2 x 10^18. When a sequence is exhausted, any INSERT that triggers a nextval() fails with "integer out of range"—a hard outage.

Many applications start with SERIAL (int4), assuming they'll never exceed 2 billion rows, then find themselves there faster than expected due to high-volume writes, soft-deletes, or ephemeral records. insightral fires at 75% utilisation, giving lead time for the migration. The migration from int4 to int8 requires a table rewrite, which should be planned as a maintenance event.

Detection SQL

Run this query with a read-only role. No writes, no locks.

-- Sequences where current value is > 75% of the max value
SELECT
  s.schemaname,
  s.sequencename,
  s.data_type,
  s.last_value,
  s.max_value,
  round(
    s.last_value::numeric / s.max_value::numeric * 100,
    2
  )                           AS used_pct,
  s.max_value - s.last_value  AS remaining
FROM pg_sequences s
WHERE s.last_value IS NOT NULL
  AND s.last_value::numeric / s.max_value::numeric > 0.75
ORDER BY used_pct DESC;

Fix SQL

Replace placeholders in <angle brackets> with values from the detection output before running.

-- For a SERIAL (int4) column: migrate to bigint (requires table rewrite)
-- Step 1: add the new bigint column
ALTER TABLE <table_name> ADD COLUMN id_new bigint;

-- Step 2: backfill (can be batched)
UPDATE <table_name> SET id_new = id WHERE id_new IS NULL;

-- Step 3: swap and clean up (in a transaction)
BEGIN;
  ALTER TABLE <table_name> DROP CONSTRAINT <pk_name>;
  ALTER TABLE <table_name> RENAME COLUMN id TO id_old;
  ALTER TABLE <table_name> RENAME COLUMN id_new TO id;
  ALTER TABLE <table_name> ADD PRIMARY KEY (id);
  ALTER TABLE <table_name> DROP COLUMN id_old;
COMMIT;

-- Simpler option if the column type is already bigint: just reset the sequence start
SELECT setval('<sequence_name>', <new_start_value>);

Worked example

Table: events.id SERIAL (int4). Application logs ~500K events/day. At current rate: sequence exhausts in approximately 14 months (last_value = 1.6B / max 2.1B = 76%). The migration to BIGSERIAL was completed in a 2-hour maintenance window with pg_repack to avoid exclusive table lock during the backfill phase.

Common false positives

  • Sequences used for sharding key generation that wrap intentionally — these use CYCLE and are not subject to exhaustion.
  • BIGSERIAL sequences showing high percentage — at 9.2 x 10^18 max, even 75% utilisation is astronomically far from practical exhaustion; this rule primarily targets int4 sequences.

Check for sequence near exhaustion across your whole estate.

Insightral runs this rule — and 98 more — continuously inside your private cloud, with read-only credentials and nothing leaving your network.

Request early access

Last updated: 2026-05-13 · View all published rules