# cPanel Exim Queue Stuck: Flush, Thaw and Delete Frozen Mail

Source: https://srvscripts.com/guides/cpanel-exim-queue-stuck/
Updated: 2026-10-07
Publisher: srvScripts (https://srvscripts.com/)

**Short answer:** Count the queue with `exim -bpc`, see who it belongs to with `exim -bp | exiqsumm`, and read why one message is stuck with `exim -Mvl <id>`. Retry everything with `exim -qff` only after you know the queue is legitimate. Remove frozen or spam mail by piping `exiqgrep -i` (filter by `-z`, `-f` sender or `-r` recipient) into `exim -Mrm`. If the queue keeps refilling, find the script or mailbox behind it before you flush anything.

We ran the read-only commands on this page (`exim -bpc`, `exim -bp`, `exiqsumm`, `exiqgrep`, `exiwhat`, `exim -Mvh`/`-Mvl`, `exigrep`) on our lab server (AlmaLinux 9.8, cPanel & WHM 11.138, Exim 4.100.1) on 6 October 2026. The commands that deliver, thaw or delete mail were checked against the Exim specification (linked below) but not run on the lab, because they change the queue.

## Check how big the queue is and who owns it

Start with numbers, not with a flush. These commands only read the spool in `/var/spool/exim`:

```
exim -bpc                  # total messages in the queue
exim -bp | exiqsumm        # summary per recipient domain
exiqgrep -c                # count (accepts the same filters as below)
exiqgrep -z -c             # how many are frozen
```

On our lab the queue held four messages, all frozen. This is the real output, with addresses and the hostname masked:

```
# exim -bpc
4

# exim -bp | head
 8h  2.0K 1xDpOc-00000000F4S-3Blx  *** frozen ***
          [masked]

 8h  2.1K 1xDpOd-00000000F4h-0p4c  *** frozen ***
          [masked]

# exim -bp | exiqsumm
Count  Volume  Oldest  Newest  Domain
-----  ------  ------  ------  ------
    4    8396      8h      8h  [server hostname]
---------------------------------------------------------------
    4    8396      8h      8h  TOTAL
```

How to read `exim -bp`: age, size, message ID, sender in angle brackets, then the recipients. A sender of `<>` means the message is a bounce (a delivery status notification). Hundreds of `<>` messages to many outside domains usually means someone sent spam from the server and the bounces are coming back.

If the queue is very large, `exim -bp` can take a long time because it sorts by arrival time. `exim -bpr` skips the sorting, and `exim -bpc` just counts.

## Find out why a message is stuck

Take one message ID from the list and look at its headers and its message log:

```
exim -Mvh 1xDpOc-00000000F4S-3Blx   # header spool file (-H)
exim -Mvl 1xDpOc-00000000F4S-3Blx   # message log: every delivery attempt
exim -Mvb 1xDpOc-00000000F4S-3Blx   # body (-D), useful to spot spam content
exigrep 1xDpOc-00000000F4S-3Blx /var/log/exim_mainlog
```

On the lab, the message log explained the freeze in one line:

```
2026-10-05 15:34:50 Received from  R=1xDpOc-00000000F4L-2EX0 U=mailnull P=local S=2043 T="Mail delivery failed: returning message to sender"
2026-10-05 15:34:50 [masked] R=localuser_root : root cannot accept local mail deliveries
*** Frozen (delivery error message)
```

This is a common pattern on cPanel. Something on the server mailed `root@` the hostname, the delivery failed, and the bounce was addressed back to root. cPanel’s `localuser_root` router in `/etc/exim.conf` refuses local delivery to root with `:fail: root cannot accept local mail deliveries`. Exim cannot bounce a bounce, so it freezes it. The `R=` value is the ID of the original message: grep the main log for it to see what sent it, fix that, and then remove the frozen bounces.

Other reasons you will see in `-Mvl` or `/var/log/exim_mainlog`:

- **Remote temporary errors** (4xx, greylisting, “try again later”): the message stays queued and Exim retries on its schedule. These are not frozen.

- **Rejections for your IP** (blocklist or rate limiting at Gmail, Microsoft and others): see our [IP blacklisted runbook](/guides/runbook-ip-blacklisted/).

- **Frozen (delivery error message)**: a bounce that could not be delivered. These are usually safe to remove.

- **Messages held by sending limits**, for example a domain that hit its hourly limit: covered in [Exim outbound mail limits in WHM](/guides/exim-outbound-mail-limits-whm/).

## Flush the queue: force delivery safely

Do not force a queue run while you still suspect spam. A forced run sends every queued spam message out at once and makes a blocklisting much more likely. Check the sender list first (next sections) and remove spam before you flush.

Once the queue is legitimate (for example after a network or DNS outage), use one of these:

```
exim -qf                       # force a delivery attempt for every NON-frozen message
exim -qff                      # same, but frozen messages are included
exim -M 1xDpOc-00000000F4S-3Blx    # one message (frozen messages are thawed first)
exim -Rff example.com          # every message with a recipient at example.com, frozen ones too
```

According to the Exim specification, one `f` forces delivery for every non-frozen message regardless of retry times, while `ff` includes frozen messages too. `-M` ignores retry hints and thaws frozen messages before trying. Messages that are being delivered at that moment are left alone.

In WHM, the same actions live in **Mail Queue Manager** (search WHM for “Mail Queue”): search by sender, recipient or date, then use **Deliver Selected**, **Deliver All**, **Delete Selected** or **Delete All**. Frozen messages show an unfreeze icon, and the WHM documentation notes it unfreezes one message at a time. For more than a handful of messages, the command line is faster.

## Thaw or remove frozen messages

Thawing tells Exim to try a frozen message again on the next queue run. Do this only when you fixed the reason it froze:

```
exim -Mt 1xDpOc-00000000F4S-3Blx           # thaw one message
exiqgrep -z -i | xargs -r exim -Mt          # thaw all frozen messages
```

Most frozen messages on a cPanel server are undeliverable bounces. Removing them is the usual fix. Save the list first so you can explain later what was deleted:

```
exiqgrep -z -c                                    # 1. how many
exiqgrep -z > /root/frozen-$(date +%F).txt        # 2. keep a record (long format)
exiqgrep -z -i | xargs -r exim -Mrm               # 3. remove them
exiqgrep -z -c                                    # 4. should now report 0 matches
```

`exim -Mrm` removes a message without sending any bounce. If you want the sender to be told, use `exim -Mg <id>` (“give up”) instead: for normal messages Exim sends a delivery failure notice to the sender, and bounces are simply discarded.

Never delete files under `/var/spool/exim/input` by hand. Each message has a -H and a -D file, and Exim also keeps hints databases. Removing files directly can leave half-messages and lock errors. Use `exim -Mrm`, which also skips messages that are being delivered at that moment.

## Bulk-delete mail by sender, recipient, domain or age

`exiqgrep` selects messages and prints their IDs with `-i`. The patterns are regular expressions. Always run the same filter with `-c` (count) or without `-i` (long list) before you pipe it into `exim -Mrm`.

| Goal | Check first | Then delete |
| --- | --- | --- |
| All mail from one sender | exiqgrep -c -f 'bob@example.com' | exiqgrep -i -f 'bob@example.com' | xargs -r exim -Mrm |
| All mail from one domain | exiqgrep -c -f '@example\.com>' | exiqgrep -i -f '@example\.com>' | xargs -r exim -Mrm |
| All bounces (sender ) | exiqgrep -c -f '^$' | exiqgrep -i -f '^$' | xargs -r exim -Mrm |
| Mail to one recipient domain | exiqgrep -c -r '@gmail\.com$' | exiqgrep -i -r '@gmail\.com$' | xargs -r exim -Mrm |
| Older than 2 days | exiqgrep -c -o 172800 | exiqgrep -i -o 172800 | xargs -r exim -Mrm |

Notes from the `exiqgrep -h` help on our lab: `-f` matches the sender field, which is wrapped in angle brackets, so `'^<>$'` matches only the empty bounce sender. `-o` and `-y` take seconds (older than / younger than). `-z` limits the match to frozen messages and `-x` to non-frozen ones, and both combine with the other filters. For example, `exiqgrep -z -f '^<>$' -i` lists only frozen bounces.

With tens of thousands of IDs, `xargs` splits the list into batches automatically. The `-r` flag stops it from running `exim -Mrm` with no arguments when nothing matched.

## Find the script or mailbox that filled the queue

Deleting spam without finding the source only buys you an hour. Look for the source from three angles:

- **Which local user and directory?** Mail sent by PHP or cron is logged with a `cwd=` (working directory) entry in `/var/log/exim_mainlog`. Count them: `grep -o 'cwd=/home[^ ]*' /var/log/exim_mainlog | sort | uniq -c | sort -rn | head`. A busy `cwd=/home/bob/public_html/wp-content/uploads/...` is a strong hint of an uploaded mailer script.

- **Which mailbox login?** SMTP-authenticated mail is logged with the authenticator name. On cPanel these are `dovecot_login` and `dovecot_plain` (we confirmed this with `exim -bP authenticator_list`). Count logins: `grep -o 'A=dovecot_[a-z]*:[^ ]*' /var/log/exim_mainlog | sort | uniq -c | sort -rn | head`. One mailbox sending thousands of messages usually has a stolen password.

- **Which PHP file?** When PHP’s `mail.add_x_header` is On (it was On for ea-php83 on our lab), PHP adds an `X-PHP-Originating-Script` header that names the UID and script. Read it with `exim -Mvh <id>` on a few spam messages.

`exiwhat` shows what each running Exim process is doing right now. On a quiet server it shows just the daemon; during a spam run it shows deliveries in progress. The Exim manual warns that it signals every Exim process, so run it when you need it, not from a tight loop. Our lab output:

```
# exiwhat
17170 daemon(4.100.1): [0+0] -q15m, listening for SMTP on port 25 (IPv6 and IPv4) port 587 (IPv6 and IPv4) and for SMTPS on port 465 (IPv6 and IPv4)
```

Once you know the source: change the mailbox password, remove the script, and set per-domain limits. The full process is in [find the source of outgoing spam on cPanel](/guides/find-source-of-outgoing-spam-cpanel/). Our [Exim Mail Queue Report](/scripts/exim-mail-queue-report/) script gives the per-sender and per-domain view in one run.

## Check that it worked

```
exim -bpc                          # should be falling, or 0
exiqgrep -z -c                     # frozen count
exim -bp | exiqsumm | tail -3      # what is left, by domain
tail -f /var/log/exim_mainlog      # watch new deliveries: "=>" delivered, "**" failed, "==" deferred
```

Check again after 30 minutes and again the next day. A queue that grows back to the same size means the source is still active.

## Common problems

- **The queue refills within minutes.** The compromised script or mailbox is still sending. Find it as shown above. As a stopgap, suspend outgoing email for that cPanel account (the WHM API 1 function is `suspend_outgoing_email`, for example `whmapi1 suspend_outgoing_email user=bob`), and lift the suspension after cleanup.

- **“Message is frozen” repeats every 15 minutes in the log.** That is the queue runner (the daemon on our lab runs with `-q15m`) skipping the frozen message. It is harmless but noisy. Remove or thaw the message.

- **`exim -Mrm` says nothing happened for some IDs.** Messages that are being delivered at that moment are not changed. Run the same command again a minute later.

- **Legitimate mail stuck as “deferred” to one provider.** Do not keep forcing it with `-qff`. Read the 4xx/5xx text in `-Mvl`. It usually points to reputation, PTR, SPF or DKIM, which a flush does not fix.

- **A huge queue makes WHM Mail Queue Manager time out.** Use `exiqgrep` and `exim -Mrm` on the command line instead.

**Official documentation:** [Exim specification: the Exim command line](https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html) · [Exim specification: Exim utilities (exiqgrep, exiwhat, exiqsumm)](https://www.exim.org/exim-html-current/doc/html/spec_html/ch-exim_utilities.html) · [cPanel docs: Mail Queue Manager](https://docs.cpanel.net/whm/email/mail-queue-manager/)

**Related:** [Outgoing Spam cPanel: Find the Source and Stop It](/guides/find-source-of-outgoing-spam-cpanel/) · [Exim Outbound Mail Limits WHM: Stop Spam Runs Fast](/guides/exim-outbound-mail-limits-whm/) · [Exim Mail Queue Report](/scripts/exim-mail-queue-report/) · [Mail server IP blacklisted: delisting runbook](/guides/runbook-ip-blacklisted/) · [Exim 4.100 Security Fixes: Critical 2026 Changes for Hosting](/guides/exim-4-100-security-fixes/)

**See also:** [SMTP Bounce Explainer: What Your Bounce Message Means](/tools/smtp-bounce-explainer/) · [Spamhaus 550 5.7.1 Blocked: Fix SBL, XBL, CSS, PBL and DBL](/guides/spamhaus-550-5-7-1-blocked/)

**See also:** [Exim Log Cheat Sheet: exigrep, exiqgrep, eximstats and Log Flags](/guides/exim-log-cheat-sheet/) · [Exim “Retry Time Not Reached for Any Host”: Causes and Fix](/guides/exim-retry-time-not-reached/)

## Frequently asked questions

### How do I flush the Exim queue on cPanel?

Run exim -qf to force a delivery attempt for all non-frozen messages, or exim -qff to include frozen ones. Check the queue for spam first, because a forced run sends everything that is queued.

### How do I delete all frozen messages in Exim?

Count them with exiqgrep -z -c, save the list with exiqgrep -z, then run exiqgrep -z -i | xargs -r exim -Mrm. Check again with exiqgrep -z -c.

### What is the difference between exim -Mrm and exim -Mg?

exim -Mrm removes the message silently. exim -Mg gives up on delivery: for normal messages the sender gets a failure notice, and bounce messages are discarded.

### Why are messages frozen with “root cannot accept local mail deliveries”?

cPanel’s Exim configuration refuses local delivery to root. A bounce addressed to root then cannot be delivered or bounced again, so Exim freezes it. Find the original message from the R= ID in the message log, fix what sent it, and remove the frozen bounces.

### Is it safe to delete files in /var/spool/exim/input?

No. Use exim -Mrm instead. It removes both spool files and leaves alone any message that is being delivered at that moment.
