tutorials/mysql/truncate-table

MySQL TRUNCATE TABLE: Foreign Keys, Rollback and DELETE

TRUNCATE TABLE removes every row from a MySQL table in one fast step. Run it from the 1bench sidebar with a typed confirmation, or in SQL, where you can also get past foreign keys, clear a single partition or empty a whole database.

Updated Nov 2, 2026Tested against MySQL 8.4.9 LTS and 9.7.4

Quick answer

In 1bench
Right-click the table in the sidebar, choose Truncate Table, type TRUNCATE and click Truncate Table.
In SQL
sql
TRUNCATE TABLE order_items;

It resets AUTO_INCREMENT and commits on the spot, so it cannot be rolled back. A table that another table references fails with ERROR 1701.

1bench
No SQL needed

Truncate a table visually in 1bench

1bench empties a MySQL table from the sidebar's right-click menu and asks you to type a confirmation word first, so a stray click cannot wipe a table.

Prerequisite: download 1bench. Free 7-day trial, no sign-up.

  1. 1

    Open the connection

    Connect to your MySQL server in 1bench and expand the database in the sidebar.

  2. 2

    Choose Truncate Table

    Right-click the table and choose Truncate Table. Views do not get this option, and on a read-only connection it is greyed out.

  3. 3

    Type TRUNCATE to confirm

    The Truncate Table dialog warns that this will permanently delete all data in the table and keep its structure. The Truncate Table button stays disabled until you type TRUNCATE in the box.

  4. 4

    Check the result

    A toast reports Truncated followed by the table name, and the open table refreshes empty. If MySQL refuses, the toast starts with Failed: and shows the server's error.

Good to know
  • 1bench runs a plain TRUNCATE TABLE with no other statements around it. A table that another table points to with a foreign key, such as users in the demo database, fails with ERROR 1701. Use the SET FOREIGN_KEY_CHECKS script below in the Query panel instead (open any table and click Query in the bottom bar).
  • SET FOREIGN_KEY_CHECKS = 0 typed in the Query panel does not carry over to the right-click Truncate Table, which runs on a different connection. Put the TRUNCATE statements in the same Query panel script.
  • The AUTO_INCREMENT counter goes back to 1, and there is no undo. Export the table first if you might want the rows back.
  • Import Data has its own Clear target table before importing option. On InnoDB it deletes the rows inside the import's transaction, so a failed import puts them back.
The manual way

Truncate a table with SQL

deletes every row in a table and keeps the table, its columns, indexes and grants. MySQL does this by dropping and recreating the table, so it takes a fraction of a second whatever the size, resets and cannot be undone.

sql
TRUNCATE TABLE order_items;

The examples use the 1bench demo database, , where , and reference , and references and . Every statement was run on MySQL 8.4 LTS and 9.7, and they behave the same on both.

TRUNCATE TABLE syntax

The full syntax is one table name, with the keyword optional. There is no , no , no and no way to list several tables.

sql
TRUNCATE TABLE order_items;
TRUNCATE order_items;
TRUNCATE TABLE saas_app.order_items;

MySQL answers however many rows were removed, because it never counts them. A view is not a table here: on a view fails with . To remove only some rows, use .

Truncate a table with foreign keys

MySQL refuses to truncate a table that another table references, even when the referencing table is empty. Trying it on gives:

text
ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint (`saas_app`.`orders`, CONSTRAINT `fk_orders_user`)

The message names only the first constraint it finds. on the child does not help, since TRUNCATE ignores it, and is a syntax error (ERROR 1064). List every table that points at the one you want to clear:

sql
SELECT TABLE_NAME, CONSTRAINT_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE REFERENCED_TABLE_SCHEMA = 'saas_app'
  AND REFERENCED_TABLE_NAME = 'users';

Then switch off foreign key checks for your session, truncate the children and the parent, and switch them back on. is a session setting, so all of it has to run on one connection.

Example: empty and everything that depends on it.

sql
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE order_items;
TRUNCATE TABLE orders;
TRUNCATE TABLE subscriptions;
TRUNCATE TABLE audit_log_v2;
TRUNCATE TABLE users;
SET FOREIGN_KEY_CHECKS = 1;

Truncate the children too, not just the parent. With checks off, MySQL lets you truncate alone and leaves full of rows pointing at user ids that no longer exist. Since TRUNCATE also resets , the next user you insert gets id 1 and quietly inherits the old orders of user 1. Turning the checks back on does not re-check existing rows.

If you would rather keep foreign keys on, delete in dependency order instead (children first). It is slower, but every row is checked.

Reset AUTO_INCREMENT

TRUNCATE always resets the counter to 1, even when the table was created with a higher start such as . DELETE keeps counting from where it was.

Example: compare the next id after each.

sql
TRUNCATE TABLE order_items;
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES (1, 1, 1, 9.99);
SELECT id FROM order_items;   -- 1

DELETE FROM order_items;
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES (1, 1, 1, 9.99);
SELECT id FROM order_items;   -- 2

To reset the counter after a DELETE, or to start somewhere other than 1 after a TRUNCATE, set it yourself. On an empty table InnoDB takes any value; on a table with rows it uses the next id above the current maximum.

sql
ALTER TABLE order_items AUTO_INCREMENT = 1;

TRUNCATE vs DELETE vs DROP

All three get rid of rows, but they differ in what they keep and what they cost. The timings are from a 500,000-row InnoDB table on the same machine.

TRUNCATE TABLEDELETE FROMDROP TABLE
RemovesAll rowsAll rows, or those matching WHERERows and the table itself
WHERE clauseNoYesNo
Speed, 500k rows0.03 to 0.04 s0.9 s (9.7) to 1.9 s (8.4)Fast
DELETE triggers fireNoYes, once per rowNo
RollbackNo, implicit commitYes, inside a transactionNo, implicit commit
AUTO_INCREMENTReset to 1KeptGone with the table
Binary log (row format)One statement, under 400 bytesOne event per batch of rows, 79 MBOne statement
Disk spaceReturned to the OSKept in the .ibd fileReturned to the OS
Referenced by a foreign keyFails, ERROR 1701Checked row by rowFails, ERROR 3730
Privilege neededDROPDELETEDROP

The binary log row matters on replicas: a DELETE of every row ships every row, while TRUNCATE ships one short statement even with . Use DELETE when you need a WHERE clause, triggers or a rollback, TRUNCATE to empty a table you are keeping, and DROP when the table itself should go.

TRUNCATE inside a transaction

TRUNCATE causes an implicit commit. Inside a transaction, it first commits whatever you had already done, then truncates, and a later ROLLBACK has nothing left to undo.

Example: the update survives the rollback, and so does the truncate.

sql
START TRANSACTION;
UPDATE users SET status = 'inactive' WHERE id = 1;
TRUNCATE TABLE order_items;
ROLLBACK;

SELECT COUNT(*) FROM order_items;           -- 0
SELECT status FROM users WHERE id = 1;      -- inactive

If you need to empty a table and keep the option to back out, use inside the transaction instead.

Truncate all tables in a database

MySQL has no single statement for this. Generate one TRUNCATE per base table from , skipping views, and run the list with foreign key checks off.

sql
SELECT CONCAT('TRUNCATE TABLE `', TABLE_NAME, '`;') AS stmt
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'saas_app'
  AND TABLE_TYPE = 'BASE TABLE';

Example: do it in one line from the shell, which pipes the generated statements straight back into mysql.

bash
mysql -u root -p -N -e "SELECT CONCAT('TRUNCATE TABLE \`', TABLE_NAME, '\`;') FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'saas_app' AND TABLE_TYPE = 'BASE TABLE'" \
  | (echo 'SET FOREIGN_KEY_CHECKS = 0;'; cat) \
  | mysql -u root -p saas_app

The order of the tables does not matter while the checks are off, and they are back on when that mysql session ends. To also remove the tables themselves, is shorter.

Truncate a partition

On a partitioned table, empties one or more partitions and leaves the rest. It is the fast way to purge old data from a table split by date.

Example: a log table partitioned by year.

sql
CREATE TABLE events (
  id INT NOT NULL,
  created_at DATE NOT NULL,
  PRIMARY KEY (id, created_at)
)
PARTITION BY RANGE (YEAR(created_at)) (
  PARTITION p2024 VALUES LESS THAN (2025),
  PARTITION p2025 VALUES LESS THAN (2026),
  PARTITION pmax VALUES LESS THAN MAXVALUE
);

ALTER TABLE events TRUNCATE PARTITION p2024;
ALTER TABLE events TRUNCATE PARTITION p2025, pmax;
ALTER TABLE events TRUNCATE PARTITION ALL;

A wrong name fails with . Do not check the result in : its column is an estimate from table statistics and can show 0 for partitions that still hold rows. Use instead.

TRUNCATE privileges

There is no TRUNCATE privilege in MySQL. TRUNCATE needs DROP on the table, and the DELETE privilege alone gets .

sql
GRANT DROP ON saas_app.order_items TO 'app'@'%';

Grant it on single tables rather than the whole database where you can. The same privilege lets the user run , and in testing that is exactly what it allowed.

When TRUNCATE hangs

TRUNCATE needs an exclusive metadata lock on the table, so it waits for any open transaction that has read or written that table, even an idle one. While it waits, shows the state , and new queries on the table queue up behind it. The sys schema names the session in the way and writes the KILL statement for you:

sql
SELECT object_name, waiting_pid, waiting_query, blocking_pid, sql_kill_blocking_connection
FROM sys.schema_table_lock_waits;

Commit in the blocking session, or run the it suggests, and TRUNCATE finishes at once. Killing the session rolls back its open transaction. To fail fast instead of waiting a year (the default is 31536000 seconds), set a short timeout first. The wait then ends with .

sql
SET SESSION lock_wait_timeout = 10;
TRUNCATE TABLE order_items;

Work with MySQL in one window

1bench is a desktop GUI for MySQL. Browse tables, filter rows, run SQL and export what you see, with the SQL still there when you want it.

Open MySQL in 1bench

Frequently asked questions

Can you roll back a TRUNCATE in MySQL?
No. TRUNCATE commits at once, and a ROLLBACK afterwards changes nothing. The way back is a backup plus the binary log: restore the backup, find the TRUNCATE in the log with SHOW BINLOG EVENTS, and replay the log up to just before it with mysqlbinlog --stop-position. Because the log stores TRUNCATE as a single statement, it is easy to spot.
Can MySQL truncate multiple tables in one query?
No. TRUNCATE TABLE takes one table, and a comma list fails with ERROR 1064 near the comma. Write one TRUNCATE TABLE per table in the same script, or generate the list from information_schema.TABLES as shown above. MySQL's DROP TABLE accepts several tables, but TRUNCATE does not.
Is there TRUNCATE TABLE IF EXISTS in MySQL?
No, MySQL rejects it with ERROR 1064 near 'IF EXISTS'. Truncating a missing table fails with ERROR 1146 (42S02): Table 'saas_app.order_item' doesn't exist. In a script, run the mysql client with --force to carry on past that error, or build the TRUNCATE statements from information_schema.TABLES so only tables that exist are listed.
Why does TRUNCATE TABLE say 0 rows affected?
MySQL empties the table by recreating it instead of deleting rows one by one, so it never counts them. Query OK, 0 rows affected is normal even when the table had half a million rows. Run SELECT COUNT(*) first if you need the number for a log.
Does TRUNCATE free disk space in MySQL?
Yes, for InnoDB tables in their own .ibd file, which is the default (innodb_file_per_table = ON). In a test, a 100 MB .ibd file dropped to 112 KB after TRUNCATE, while DELETE left it at 100 MB until OPTIMIZE TABLE rebuilt it. Tables created while innodb_file_per_table was off live in the shared ibdata1 file, which never shrinks.