Resolving Database Migration Failures During Forgejo Updates
A diagnostic guide for resolving 'Database Migration Failed' errors in Forgejo. Learn how to identify schema mismatches, verify SQL permissions, and safely recover from interrupted updates.
18 Feb 2026, 00:50 UTC

The Problem: Migration Failures on Startup
When updating Forgejo, the application performs a schema migration to ensure the database structure matches the requirements of the new binary. If this process fails, the application will refuse to start, often entering a crash loop or displaying a critical error page. The primary takeaway is that migration failures are usually caused by insufficient database permissions or interrupted state transitions, and they should never be fixed by manually editing version tables without a verified backup.
Diagnostic Matrix
Identify your specific failure state by searching the forgejo.log or the container stdout for the following strings.
| Log String | Likely Cause | Primary Suspect |
|---|---|---|
migration failed: permission denied |
Insufficient SQL privileges | Database User Role |
version mismatch or migration not found |
Incorrect binary version or skipped milestone | Deployment Tag/Image |
table already exists or column already exists |
Interrupted previous migration | Database State |
Step-by-Step Recovery Process
Follow these checks in order. Do not proceed to the next step if the current step resolves the issue.
1. Verify Database Connectivity and Permissions
Forgejo requires the ability to modify the schema (ALTER TABLE, CREATE TABLE, DROP INDEX) during updates. If you are using a managed database service, ensure the user hasn't been restricted to DML (Data Manipulation Language) only.
- Check: Attempt to run a dummy schema change using the same credentials Forgejo uses.
- Action: If using PostgreSQL, ensure the user is the owner of the database or has
SUPERUSER/CREATEDBroles during the migration window.
2. Validate Binary Version Alignment
Running a binary that is older than the current database schema, or skipping a mandatory intermediate version, can trigger migration errors. Forgejo updates should generally follow a linear path.
- Check: Verify the image tag or binary version. Avoid using
latestin production; use specific semantic version tags (e.g.,7.0.1). - Action: If you jumped multiple major versions, revert to the last stable version and upgrade through the intermediate milestones specified in the official release notes.
3. Inspect the Version Table
Forgejo tracks its schema state in a internal version table. If a migration was interrupted (e.g., the container was killed mid-update), the database may be in a "partial" state.
- Check: Use a SQL client to query the current version.
-- Run on your SQL host as a DB admin SELECT * FROM version; - Risk: Do not manually update this value to "trick" the application into starting. This will lead to
column not founderrors during runtime.
Fixes Based on Findings
Scenario A: Interrupted Migration (Partial State)
If the logs indicate that a column already exists or a table was partially created, the database state is inconsistent.
- Rollback: Stop the Forgejo service immediately.
- Restore: Restore the database from the backup taken immediately prior to the update attempt.
- Retry: Ensure the database has enough disk space and the system has sufficient memory to complete the migration, then restart the update.
Scenario B: Permission Denied
If the logs explicitly mention permission failures during ALTER commands:
- Elevate: Temporarily grant the Forgejo database user
OWNERstatus on the schema. - Restart: Restart the Forgejo binary to trigger the migration.
- Restrict: Once the application starts successfully, revert the permissions to the minimum required for daily operation.
Verification and Escalation
To verify the fix, check the /admin/config panel (if accessible) or use the admin CLI to confirm the installed version matches the binary version.
Practical Verification Check:
Review the database schema for a column introduced in the latest release. For example, if the release notes mention a new last_active_at column in the user table, run:
-- Run on SQL host
SELECT column_name FROM information_schema.columns WHERE table_name = 'user' AND column_name = 'last_active_at';
If the column is present and the application is running, the migration succeeded.
When to Escalate
Contact the community or maintainers if:
- The migration fails with a
Unique Constraint Violationon a table that should not have duplicate data. - Restoring from backup and retrying the update results in the exact same failure at the same migration step.
- The
versiontable is empty or corrupted despite a successful database restore.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.