How to Fix Email Account Disk Usage Display in cPanel (dovecot-quota)

How to Fix Email Account Disk Usage Display in cPanel

If you notice that email account disk usage in cPanel displays in KB (e.g., 78 KB) when the actual usage is several GB, this is caused by a synchronization issue between the Dovecot quota files and the cPanel cache.

Info
This procedure requires SSH access with root privileges on the server. The commands use variables that must be replaced before execution: USER (cPanel username) and DOMAIN (mail domain).

🔍 Root Cause

The dovecot-quota file inside each mailbox is responsible for storing the account's disk usage. When this file is missing or contains incorrect values, cPanel displays outdated data. Additionally, the cPanel datastore caches these values and does not refresh them automatically.

📋 Identify the Variables

Before starting, retrieve the cPanel username associated with the domain:

grep DOMAIN /etc/userdomains

The output will display something like: domain1.com.mx: domain1c — where domain1c is the USER and domain1.com.mx is the DOMAIN.


Step 1 — Verify Actual Disk Usage

Confirm the actual disk space consumed by each email account on the server:

du -sh /home/USER/mail/DOMAIN/*/

If the values match what cPanel displays, no further action is needed. If there are significant discrepancies (cPanel shows KB when the actual usage is MB or GB), proceed with the following steps.


Step 2 — List Email Accounts

Retrieve the list of email accounts registered in cPanel for the domain:

uapi --user=USER Email list_pops_with_disk | grep "email:"


Step 3 — Create/Rebuild the dovecot-quota Files

This script removes any existing dovecot-quota files, recalculates quotas through Dovecot, and writes the correct values for each account:

for account in $(ls /home/USER/mail/DOMAIN/); do
rm -f /home/USER/mail/DOMAIN/${account}/dovecot-quota
doveadm quota recalc -u "${account}@DOMAIN" 2>/dev/null
QUOTA=$(doveadm quota get -u "${account}@DOMAIN" 2>/dev/null \
| grep "Mailbox" | grep "STORAGE" | awk '{print $3}')
MESSAGES=$(doveadm quota get -u "${account}@DOMAIN" 2>/dev/null \
| grep "Mailbox" | grep "MESSAGE" | awk '{print $3}')
if [ -n "$QUOTA" ]; then
MAILPATH="/home/USER/mail/DOMAIN/${account}"
echo "priv/quota/storage=${QUOTA}" > "${MAILPATH}/dovecot-quota"
echo "priv/quota/messages=${MESSAGES}" >> "${MAILPATH}/dovecot-quota"
chown USER:USER "${MAILPATH}/dovecot-quota"
echo "${account}: storage=${QUOTA} messages=${MESSAGES}"
fi
done

Each account will print its name along with the storage and message count values. Verify that these match the output from Step 1.


Step 4 — Flush the cPanel Cache

Remove the datastore cache files to force a fresh read:

rm -f /home/USER/.cpanel/datastore/*email*
rm -f /home/USER/.cpanel/datastore/*quota*
rm -f /home/USER/.cpanel/datastore/_Cpanel::Quota*


Step 5 — Restart cpsrvd

Restart the cPanel service so the web interface picks up the updated data:

/scripts/restartsrv_cpsrvd

Warning
This command restarts cpsrvd for all users on the server. It is recommended to run it during off-peak hours.


Step 6 — Force UI Refresh (Quota Toggle)

This step reads the current quota for each account, temporarily sets it to 500 MB, and then restores it to the original value, forcing cPanel to refresh the displayed data in the web interface:

for account in $(ls /home/USER/mail/DOMAIN/); do
# Read the current quota before modifying
CURRENT_LIMIT=$(doveadm quota get -u "${account}@DOMAIN" 2>/dev/null \
| grep "^Mailbox" | grep "STORAGE" | awk '{print $4}')

if [ "$CURRENT_LIMIT" = "-" ] || [ -z "$CURRENT_LIMIT" ]; then
RESTORE_QUOTA=0
else
RESTORE_QUOTA=$((CURRENT_LIMIT / 1024))
fi

# Toggle to force refresh
uapi --user=USER Email edit_pop_quota \
email=${account} domain=DOMAIN quota=500 2>/dev/null
# Restore original quota
uapi --user=USER Email edit_pop_quota \
email=${account} domain=DOMAIN quota=${RESTORE_QUOTA} 2>/dev/null

echo "${account}: restored to ${RESTORE_QUOTA} MB"
done

Info
quota=0 is equivalent to unlimited in the cPanel API. If the first command returns the error "You cannot set an email account quota higher than X", lower the temporary value (e.g., quota=100).


✅ Verification

  1. Reload the cPanel page using Ctrl+F5 (hard refresh).

  2. Verify that the Storage values match the output from Step 1.

  3. If an individual account did not update, run the following for that specific account:

uapi --user=USER Email edit_pop_quota \
email=ACCOUNT domain=DOMAIN quota=500
uapi --user=USER Email edit_pop_quota \
email=ACCOUNT domain=DOMAIN quota=0


⚠️ Commands That Must NOT Be Executed

The following commands can revert the fix and must not be used after completing this procedure:

Warning
  • find /home/USER/mail/ -name "maildirsize" -delete — May cause the values to be rebuilt incorrectly.
  • /scripts/fixquotas — Overwrites the quota files with incorrect values.
  • doveadm quota recalc after Step 3 — This command is already executed within the script; running it again may overwrite the dovecot-quota file.