MP064critical

ban-disable-trigger

DISABLE TRIGGER breaks replication, audit logs, and FK enforcement.

operation
Triggers
lock taken
no table lock
remediation
Manual rewrite
category
Data safety

What triggers it

The AT_DisableTrigAll or AT_DisableTrigUser subtype of ALTER TABLEALTER TABLE ... DISABLE TRIGGER ALL or ... DISABLE TRIGGER USER.

What does not

ALTER TABLE ... DISABLE TRIGGER <name> targeting one specific trigger by name produces neither subtype and passes through, as does any AlterTableStmt with no cmds or no relation.relname, or any table alteration that doesn't touch triggers at all.

Where it applies

Applies to every PostgreSQL version MigrationPilot targets. It works on the SQL text alone — no database connection needed.

The lock, and what it blocks

No lock is named in the source — the danger isn't blocking, it's that once triggers are off, logical replication (which relies on triggers internally), audit logging, and foreign-key enforcement all silently stop working until something re-enables them.

Why it matters

ALTER TABLE DISABLE TRIGGER ALL/USER turns off all triggers on the table. This breaks logical replication (which uses triggers internally), disables audit logging triggers, and bypasses foreign key enforcement. If the session crashes before re-enabling triggers, they remain disabled permanently.

Unsafe, and safe

Flagged

ALTER TABLE users DISABLE TRIGGER ALL;

Safe alternative

-- Disable only a specific trigger temporarily
ALTER TABLE users DISABLE TRIGGER my_audit_trigger;
-- ... perform operation ...
ALTER TABLE users ENABLE TRIGGER my_audit_trigger;

What it assumes

The rule assumes the table has triggers whose loss matters — replication, audit, FK enforcement — which won't be true for every table. It also can't tell whether the same session re-enables triggers later; it flags the disable unconditionally.

What backs this rule

Every rule is a claim about PostgreSQL, so it carries what the claim rests on: a handbook chapter that cites the manual, the incidents that put it there, and the version it was last checked against.

Two migrations that look local to one table, and are not: dropping a primary key, and disabling triggers.

verified against
PostgreSQL 17.10
last checked
2026-08-11
confidence
High

What the CLI prints

migrationpilot analyze migration.sql
✗ [MP064] CRITICAL (line 1)
  DISABLE TRIGGER ALL on "users" breaks replication, audit logs, and FK enforcement. Use targeted trigger disabling or restructure the migration.

  Why: ALTER TABLE DISABLE TRIGGER ALL/USER turns off all triggers on the table. This breaks logical replication (which uses triggers internally), disables audit logging triggers, and bypasses foreign key enforcement. If the session crashes before re-enabling triggers, they remain disabled permanently.
  Docs: https://migrationpilot.dev/rules/mp064

Generated by running the CLI's own formatter over the flagged example above, so it is the text the tool actually produces. A real run also reports the other rules that fire on the same statement; those blocks are left out here.

Turning it off

For one statement, put a comment on the line before it:

-- migrationpilot-disable MP064
ALTER TABLE users DISABLE TRIGGER ALL;

For the whole project, in .migrationpilotrc.yml — by name or by id:

.migrationpilotrc.yml
rules:
  MP064: false

# or keep it, and downgrade it
rules:
  MP064:
    severity: warning

Try it

Open this rule's flagged example in the playground. It runs in your browser — edit it and watch the finding appear and disappear.

Run MP064 in the playground