Liquibase takes a row lock in DATABASECHANGELOGLOCK so two runs cannot migrate at once. If a previous run was killed before releasing it, the lock is left set and the next run waits - often forever.
What this error means
A Liquibase step prints "Waiting for changelog lock...." repeatedly and then hangs or times out. It commonly follows a cancelled or OOM-killed CI job that held the lock when it died.
liquibase output
Waiting for changelog lock....
Waiting for changelog lock....
Liquibase Community ... could not acquire change log lock.
Currently locked by runner-7 (10.0.0.7) since 2026-06-25 09:14
Common causes
Stale lock from a killed run
A prior Liquibase run was cancelled, timed out, or OOM-killed before it could release the lock. The DATABASECHANGELOGLOCK row stays "locked" and blocks every subsequent run.
Genuinely concurrent migrations
Two pipelines migrating the same database at once will legitimately contend for the lock; one waits while the other runs.
How to fix it
Release a stale lock
When you are sure no other migration is running, release the lock so the next run can acquire it.
Terminal
liquibase releaseLocks
liquibase update
Serialize migrations to avoid real contention
Use CI concurrency controls so only one migration job runs against a database at a time.
Avoid two pipelines targeting the same database concurrently.
Give the migration step a sensible timeout so a stuck lock surfaces fast instead of hanging.
How to prevent it
Constrain migration jobs with a concurrency group so they cannot overlap.
Ensure jobs release the lock on cancellation; clear stale locks at the start of a controlled deploy.
Set a step timeout so a held lock fails fast rather than hanging the pipeline.
Frequently asked questions
What causes ""Waiting for changelog lock""?
A prior Liquibase run was cancelled, timed out, or OOM-killed before it could release the lock. The DATABASECHANGELOGLOCK row stays "locked" and blocks every subsequent run.
How do I fix "Waiting for changelog lock"?
When you are sure no other migration is running, release the lock so the next run can acquire it.
Can Latchkey fix this automatically?
Yes. Latchkey runs your GitHub Actions on managed runners that detect this failure, apply the fix, and retry the job automatically - self-healing is on by default.