blog
My MySQL Database is Out of Disk Space
When the MySQL server ran out of disk space, you would see one of the following errors in your application (as well as in the MySQL error log):
ERROR 3 (HY000) at line 1: Error writing file '/tmp/AY0Wn7vA' (Errcode: 28 - No space left on device)
For binary log the error message looks like so:
[ERROR] [MY-000035] [Server] Disk is full writing './binlog.000019' (OS errno 28 - No space left on device). Waiting for someone to free space... Retry in 60 secs. Message reprinted in 600 secs.
For relay log the error message looks like so:
[ERROR] [MY-000035] [Server] Disk is full writing './relay-bin.000007' (OS errno 28 - No space left on device). Waiting for someone to free space... Retry in 60 secs. Message reprinted in 600 secs.
For slow query log you would see an error message like so:
[ERROR] [MY-011263] [Server] Could not use /var/log/mysql/mysql-slow.log for logging (error 28 - No space left on device). Turning logging off for the server process. To turn it on again: fix the cause, then either restart the query logging by using "SET GLOBAL SLOW_QUERY_LOG=ON" or restart the MySQL server.
For InnoDB it looks like so:
[ERROR] [MY-012144] [InnoDB] posix_fallocate(): Failed to preallocate data for file ./#innodb_temp/temp_8.ibt, desired size 16384 bytes. Operating system error number 28. Check that the disk is not full or a disk quota exceeded. Make sure the file system supports this function. Some operating system error numbers are described at http://dev.mysql.com/doc/refman/8.0/en/operating-system-error-codes.html
[Warning] [MY-012638] [InnoDB] Retry attempts for writing partial data failed.
[ERROR] [MY-012639] [InnoDB] Write to file ./#innodb_temp/temp_8.ibt failed at offset 81920, 16384 bytes should have been written, only 0 were written. Operating system error number 28. Check that your OS and file system support files of this size. Check also that the disk is not full or a disk quota exceeded.
[ERROR] [MY-012640] [InnoDB] Error number 28 means 'No space left on device'
[Warning] [MY-012145] [InnoDB] Error while writing 16384 zeroes to ./#
They are all reporting the same error code number which is 28. Alternatively, we can use the error code to see the actual error with the perror command:
$ perror 28
OS error code 28: No space left on device
The above simply means the MySQL server is out of disk space, and most of the time MySQL is stopped or stalled at this point. In this blog post, we are going to look into ways to solve this issue for MySQL running in a Linux-based environment.
Troubleshooting
First of all, we have to determine which disk partition is full. MySQL can be configured to store data on a different disk or partition. Look at the path as stated in the error to start with. In this example, our directory is located in the default location, /var/lib/mysql which is under the / partition. We can use the df command and specify the full path to the datadir to get the partition the data is stored:
$ df -h /var/lib/mysql
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 40G 40G 20K 100% /
The above means we have to clear up some space in the root partition.
Temporary Workarounds
The temporary workaround is to clear up some disk space so MySQL can write to the disk and resume the operation. Things that we can do if we face this kind of problem are related to:
- The removal of unnecessary files
- Purging of the binary logs
- Dropping old tables, or rebuilding a very big table
Remove Unnecessary Files
This is commonly the first step to do if MySQL server is down or unresponsive, or you have no binary logs enabled. For example, files under /var/log/ are commonly the first place to look for unnecessary files:
$ cd /var/log
$ find . -type f -size +5M -exec du -sh {} +
8.1M ./audit/audit.log.6
8.1M ./audit/audit.log.5
8.1M ./audit/audit.log.4
8.1M ./audit/audit.log.3
8.1M ./audit/audit.log.2
8.1M ./audit/audit.log.1
11M ./audit/audit.log
8.5M ./secure-20190429
8.0M ./wtmp
The above example shows how to retrieve files that are bigger than 5MB. We can safely remove the rotated log files which are usually in {filename}.{number} format, for example from audit.log.1 until audit.log.6. The same thing can be said about any huge older backups that are stored in the server. If you had performed a restoration via Percona Xtrabackup or MariaDB Backup, all files prefixed with xtrabackup_ can be removed from the MySQL datadir, as they are no longer necessary for the restoration. The xtrabackup_logfile usually is the biggest file since it contains all transactions executed while the xtrabackup process copying the datadir to the destination. The following example shows all the related files in MySQL datadir:
$ ls -lah /var/lib/mysql | grep xtrabackup_
-rw-r-----. 1 mysql root 286 Feb 4 11:30 xtrabackup_binlog_info
-rw-r--r--. 1 mysql root 24 Feb 4 11:31 xtrabackup_binlog_pos_innodb
-rw-r-----. 1 mysql root 83 Feb 4 11:31 xtrabackup_checkpoints
-rw-r-----. 1 mysql root 808 Feb 4 11:30 xtrabackup_info
-rw-r-----. 1 mysql root 179M Feb 4 11:31 xtrabackup_logfile
-rw-r--r--. 1 mysql root 1 Feb 4 11:31 xtrabackup_master_key_id
-rw-r-----. 1 mysql root 248 Feb 4 11:31 xtrabackup_tablespaces
Therefore, the mentioned files are safe to be deleted. Start MySQL service once there is at least 10% more free space.
Purge the Binary Logs
If the MySQL server is still responsive and it has binary log enabled, e.g, for replication or point-in-time recovery, we can purge the old binary log files by using the PURGE statement and providing the interval. In this example, we are deleting all binary logs before 3 days ago:
mysql> SHOW BINARY LOGS;
mysql> PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 3 DAY);
mysql> SHOW BINARY LOGS;
For MySQL Replication, it’s safe to delete all logs that have been replicated and applied on slaves. Check the Relay_Master_Log_File value on the server:
mysql> SHOW SLAVE STATUSG
...
Relay_Master_Log_File: binlog.000008
...
And delete the older log files for example binlog.000007 and older. It’s good practice to restart the MySQL server to make sure that it has enough resources. We can also let the binary log rotation to happen automatically via the expire_logs_days variable (
mysql> SET GLOBAL expire_logs_days = 3;
Then, add the following line into MySQL configuration file under the [mysqld] section:
expire_logs_days=3
In MySQL 8.0, use binlog_expire_logs_seconds instead, where the default value is 2592000 seconds (30 days). In this example, we reduce it to only 3 days (60 seconds x 60 minutes x 24 hours x 3 days):
mysql> SET GLOBAL binlog_expire_logs_seconds = (60*60*24*3);
mysql> SET PERSIST binlog_expire_logs_seconds = (60*60*24*3);
SET PERSIST will make sure the configuration is loaded in the next restart. Configuration set by this command is stored inside /var/lib/mysql/mysqld-auto.cnf.
Drop Old Tables / Rebuild Tables
Note that the DELETE operation won’t free up the disk space unless OPTIMIZE TABLE is executed afterward. Thus, if you have deleted many rows, and you would like to return the free space back to the OS after a huge DELETE operation, run the OPTIMIZE TABLE, or rebuild it. For example:
mysql> DELETE tbl_name WHERE id < 100000; -- remove 100K rows
mysql> OPTIMIZE TABLE tbl_name;
We can also force to rebuild a table by using ALTER statement:
mysql> ALTER TABLE tbl_name FORCE;
mysql> ALTER TABLE tbl_name; -- a.k.a "null" rebuild
Note that the above DDL operation is performed via online DDL, meaning MySQL permits concurrent DML operations while the rebuilding is ongoing. Another way to perform a defragmentation operation is to use mysqldump to dump the table to a text file, drop the table, and reload it from the dump file. Ultimately, we can also use DROP TABLE to remove the unused table or TRUNCATE TABLE to clear up all rows in the table, which consequently return the space back to the OS.
Permanent Solutions to Disk Space Issues
The permanent solution is of course adding more space to the corresponding disk or partition, or applying a shorter retention rule to keep unnecessary files in the server. If you are running on top of a scalable file storage system, you should be able to scale the resource up without too much hassle, or with minimal disruption and downtime to the MySQL service. To learn more on how to dimension your storage and understand MySQL and MariaDB capacity planning, check out this blog post.
Summary
Disk-related database problems are one of the most prevalent issues concerning MySQL database administrators and developers working with the RDBMS alike – however, while those issues may be prevalent, there also are a lot of ways to solve them – and solve them for good. The ways to tackle such an issue may not always be straightforward, however, they all can be solved with a little bit of effort and assistance provided by tools like ClusterControl.
With ClusterControl’s proactive monitoring capabilities, database-related issues should be the least of your worries: you will get a notification in the form of a warning when the disk space has reached 80%, and a notification in the form of a critical warning if your disk usage reaches 90% or more. We hope that this blog post has let you solve at least a couple of the issues related to MySQL disk space usage, enjoy your use of ClusterControl, and we will see you in the next blog.