O df -h mostra 94% e o banco é o suspeito. Antes de sair rodando DELETE em tabela de log (com backup do banco na mão, sempre), dá para saber em dez segundos qual delas comeu o disco. Conecte no MySQL 8 com o banco do site selecionado:
SET SESSION information_schema_stats_expiry = 0;
SELECT table_name,
ROUND((data_length + index_length) / 1024 / 1024) AS mb,
ROUND(data_length / 1024 / 1024) AS dados_mb,
ROUND(index_length / 1024 / 1024) AS indice_mb,
table_rows
FROM information_schema.TABLES
WHERE table_schema = DATABASE()
ORDER BY 2 DESC
LIMIT 15;Como ler as colunas que importam
A primeira linha não é enfeite: no MySQL 8 essas estatísticas vêm de cache com validade de um dia (information_schema_stats_expiry, padrão 86400). Sem zerar na sessão, você olha o tamanho de ontem.
data_length é o espaço das linhas; index_length é o dos índices. Índice maior que os dados costuma ser índice sobrando ou duplicado, não volume de registro. Em WordPress o topo quase sempre é wp_postmeta ou wp_options; em Magento 2, report_event e url_rewrite. Já table_rows é estimativa em InnoDB: se o número parecer absurdo, um ANALYZE TABLE nome_da_tabela; refaz a conta.
O espaço que já é seu e não voltou
SELECT table_name, ROUND(data_free / 1024 / 1024) AS livre_mb
FROM information_schema.TABLES
WHERE table_schema = DATABASE() AND data_free > 0
ORDER BY 2 DESC;data_free é o pedaço do .ibd que o InnoDB já tomou do disco e liberou só internamente depois de um DELETE grande: o sistema operacional continua vendo aquilo como ocupado. Quem devolve é o OPTIMIZE TABLE, só que ele recria a tabela do zero e precisa de espaço livre do tamanho dela enquanto trabalha.
Ou seja: com o disco em 94% o OPTIMIZE é a última coisa a tentar. Ganhe fôlego primeiro com PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);, conferindo antes que nenhuma réplica atrasada nem backup dependa daqueles binlogs, porque eles não voltam. Depois volte para a tabela campeã.