Databases

Repair Corrupted MySQL InnoDB Tables on a Linux VPS

Confirm InnoDB corruption with CHECK TABLE, start MySQL with innodb_force_recovery to dump readable data, then rebuild the tables from that dump.

AdvancedLinux server6 min read

InnoDB corruption usually appears as error 1712, "Database page corruption on disk or a failed file read", or a server that refuses to start after a power loss or a full disk. You cannot repair a corrupted InnoDB table in place the way you can with MyISAM — the recovery path is to get the server running, dump everything still readable, and rebuild the tables from that dump. This guide walks through that sequence on a Linux VPS, from confirming the damage to a clean import.

Before you start

You need:

  • Root or sudo access to the VPS, and a MySQL or MariaDB server that is installed but not necessarily running.
  • Free disk space at least the size of your data directory, so you can keep a copy of the broken files.
  • Your most recent logical backup, if you have one. Recovery is much faster when you can fall back to it.
  • The data directory path. On Ubuntu, Debian, AlmaLinux and Rocky it is normally /var/lib/mysql. Check where my.cnf lives if you are unsure about your layout.

Warning: Do not run any repair or import against the only copy of your data. Copy the data directory first, and keep the copy until you have verified the rebuilt database.

If MySQL will not start at all, you can still reach the VPS through the browser console in your VPS provider's control panel and work from there.

Confirm the damage with CHECK TABLE

Start by finding out which tables are actually broken. If the server is running, run mysqlcheck across everything:

Bash
sudo mysqlcheck -u root -p --all-databases

Healthy tables report OK. Anything else — Table is marked as crashed, Incorrect key file, Got error 176 — is a candidate. For a single table:

SQL
CHECK TABLE appdb.orders;

Then look at the engine state and the error log:

SQL
SHOW ENGINE INNODB STATUS\G

Read the LATEST FOREIGN KEY ERROR and page-corruption sections. In parallel, watch the log while you query:

Bash
sudo tail -n 100 /var/log/mysql/error.log
sudo journalctl -u mysql -n 100 --no-pager

Corruption messages name the tablespace file, for example appdb/orders.ibd, which tells you exactly which table to prioritise.

Stop writes and copy the data directory

Warning: Stop MySQL before copying files. Copying a live InnoDB data directory can produce a copy that is just as broken as the original.

Bash
sudo systemctl stop mysql
sudo mkdir -p /root/mysql-corrupt-$(date +%F)
sudo rsync -aH --info=progress2 /var/lib/mysql/ /root/mysql-corrupt-$(date +%F)/

If the server will not start, this copy is your working source. If it will start, you still want it — the recovery steps below modify the data directory.

Repair corrupted MySQL InnoDB tables with innodb_force_recovery

innodb_force_recovery tells InnoDB to skip parts of its normal startup checks so the server can come up and let you read data. Levels run from 1 to 6, and you should use the lowest level that lets the server start.

Edit your config file — usually /etc/mysql/mysql.conf.d/mysqld.cnf on Ubuntu and Debian, or /etc/my.cnf.d/mysql-server.cnf on AlmaLinux and Rocky:

INI
[mysqld]
innodb_force_recovery = 1

Then start the service and watch the log:

Bash
sudo systemctl start mysql
sudo tail -f /var/log/mysql/error.log

If startup still fails, stop the service, raise the value to 2, then 3, and so on. What the levels mean in practice:

  • 1 skips corrupt pages instead of crashing.
  • 2 prevents background purge activity.
  • 3 skips transaction rollback.
  • 4 and above make InnoDB read-only, so you can only read and dump.
  • 5 and 6 skip undo log and redo log processing — last resort before restoring a backup.

Note: MariaDB uses the same variable name and the same levels. Never leave innodb_force_recovery set once recovery is finished; it disables safety checks and writes.

Dump what you can still read

With the server up, take a logical dump immediately. This is the data you will rebuild from.

Bash
mysqldump -u root -p \
  --single-transaction --routines --triggers --events \
  --databases appdb > /root/appdb-recovered.sql

If the dump aborts on one bad table, dump table by table and skip the problem:

Bash
mysqldump -u root -p --force --databases appdb > /root/appdb-partial.sql

Or pull a single table's rows without its schema:

Bash
mysqldump -u root -p --no-create-info appdb orders > /root/orders-data.sql

At recovery level 6 you may only be able to export rows, not the full schema. In that case, recreate the table structure from your application's migrations or from a schema-only dump, then load the rows.

Rebuild the tables

Once the dump is safe, take the server out of recovery mode and rebuild.

Warning: The next step drops and recreates the database. Confirm the dump file exists and is non-empty before you continue.

Bash
sudo systemctl stop mysql

Remove the innodb_force_recovery line from your config file, then:

Bash
sudo systemctl start mysql

Recreate the schema and import:

Bash
mysql -u root -p -e "DROP DATABASE IF EXISTS appdb; CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -u root -p appdb < /root/appdb-recovered.sql

For a single damaged table you can sometimes rebuild it in place instead, which keeps the rest of the database untouched:

SQL
ALTER TABLE appdb.orders ENGINE=InnoDB;

That only works if the table is readable at the current recovery level. If it errors, fall back to the dump-and-import route.

Check it works

Run the integrity check again across all databases:

Bash
sudo mysqlcheck -u root -p --all-databases

Every table should report OK. Then:

  1. Compare row counts on your largest tables against the dump or your last backup:
SQL
   SELECT COUNT(*) FROM appdb.orders;
  1. Watch the error log for new corruption messages while your application runs its normal queries:
Bash
   sudo tail -f /var/log/mysql/error.log
  1. Run a few representative application queries and confirm the results look right, not just that they return.

Troubleshooting

  • "Table doesn't exist in engine" — the .ibd file is missing or orphaned. Check the data directory for the file, and if it is gone, restore that table from a backup.
  • Server still will not start at level 6 — the redo log or system tablespace is damaged beyond in-place recovery. Restore from a physical or logical backup and re-apply recent changes.
  • mysqldump stops with "Lost connection to MySQL server" — a table is unreadable at the current level. Raise innodb_force_recovery by one, or dump with --force and accept that one table is missing.
  • Duplicate entry errors during import — the dump already contained the rows. Drop and recreate the schema before importing, as shown above.
  • "Cannot add or update a child row" on import — foreign keys are being enforced out of order. Import with SET FOREIGN_KEY_CHECKS=0; at the top of the session, or use --single-transaction so tables load in dependency order.
  • Access denied for user 'root' — see fixing MySQL error 1045.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.