2.5TB Distribution DB. Distribution Cleanup Agent not running from 1.5 years

Sowjanya Gopal 100 Reputation points
2026-07-04T08:59:24.4933333+00:00

Distribution cleanup agent was not running from 1.5 years.

Started running it gradually by giving max_distretention hours equivalent to 1.5 years and reducing it by 15 hours in next run.

Ex: 1st run:

EXEC dbo.sp_MSdistribution_cleanup @min_distretention = 0, @max_distretention = 13500

next run:

EXEC dbo.sp_MSdistribution_cleanup @min_distretention = 0, @max_distretention = 13485

It is taking time, succeeding & deleting transactions & commands.

I can see that no of transactions in MSRepl_transactions has dropped but there is no change in min(entry_time) in msrepl_transactions.

Any idea why.

Is there any better way to cleanup Distribution DB.

Thank you.

SQL Server | Other
SQL Server | Other

Additional SQL Server features and topics not covered by specific categories

0 comments No comments

Answer accepted by question author
Deepesh Dhake 1,165 Reputation points
2026-07-06T16:38:49.8366667+00:00

Based on the analysis, there appear to be two separate issues in the distribution database:

  1. The dropped article's publication (database 9, from 17-Feb-2025 onward)

The article has been dropped, but the publication and its subscription still exist. Since that subscription is still a registered destination, the cleanup process continues to account for it, which is likely why these transactions remain. Dropping the subscription and then the empty publication should allow these transactions to be released:

-- On the Publisher, in the published database
EXEC sp_dropsubscription 
    @publication = 'YourPublication',
    @article = 'all',
    @subscriber = 'ReportingServerB',
    @destination_db = 'SubscriberDB'

EXEC sp_droppublication 
    @publication = 'YourPublication'

After running this, it would be worth running a cleanup pass and checking whether MIN(entry_time) for publisher_database_id = 9 moves forward.

  1. The Test DB rows (Dec-2024, publisher_database_id 1, 2, 4, 7, 8)

This points to orphaned distribution metadata left behind by an incomplete removal.

It's worth noting that the dropped article's entries would only persist in the same way if its removal is incomplete. If the subscription and empty publication are dropped cleanly, the transactions should become eligible and get cleaned up.

To diagnose the orphans, you could run the following in the distribution database:

USE distribution;
GO
SELECT publisher_database_id, publication_id, article_id, subscriber_id
FROM dbo.MSsubscriptions 
ORDER BY publisher_database_id

SELECT id, publisher_database_id, publication, subscriber_db, subscription_type
FROM dbo.MSdistribution_agents 
ORDER BY publisher_database_id

Was this answer helpful?

1 person found this answer helpful.

2 additional answers

Sort by: Newest
  1. Deepesh Dhake 1,165 Reputation points
    2026-07-06T15:37:06.9+00:00

    Transactions are per-publisher-database. One publisher transaction touching multiple articles produces one MSrepl_transactions row plus multiple MSrepl_commands rows tagged by article. The cleanup low-water mark advances per publisher_database_id, and sp_MSdistribution_cleanup only purges a transaction when all its commands are eligible across all subscriptions for that database. So if any article or subscription on database 9 still references a range of transactions, the whole range for database 9 stays put.

    Two separate problems in your data:

    1. The dropped article's publication (database 9, 17-Feb-2025 onward). You dropped the article, but the publication (now 0 articles) and its subscription still exist. That subscription is still a registered destination cleanup accounts for. Dropping the subscription then the empty publication should release these transactions.
    -- On Publisher, in the published database
    EXEC sp_dropsubscription 
        @publication = 'YourPublication',
        @article = 'all',
        @subscriber = 'ReportingServerB',
        @destination_db = 'SubscriberDB';
    EXEC sp_droppublication 
        @publication = 'YourPublication';
    

    Then run one cleanup pass and check whether MIN(entry_time) for publisher_database_id = 9 moves forward. It should, provided no other article on database 9 still pins those same xact_seqnos. Confirm push vs pull first: if pull, also run sp_droppullsubscription on the subscriber.

    1. The Test DB rows (Dec-2024, publisher_database_id 1, 2, 4, 7, 8). You dropped those publications and databases long ago, yet the transactions persist. That's orphaned distribution metadata from an incomplete removal, cleanup still thinks something needs them, so it never purges them.

    The dropped article's entries persist too only if its removal is incomplete. If you drop the subscription and empty publication cleanly, the transactions become eligible and get cleaned. The Test DBs prove that incomplete removal leaves permanent orphans. The difference is entirely whether the metadata is fully gone afterward.

    Diagnose the orphans (run in distribution DB):

    USE distribution;
    GO
    SELECT publisher_database_id, publication_id, article_id, subscriber_id
    FROM dbo.MSsubscriptions ORDER BY publisher_database_id;
    SELECT id, publisher_database_id, publication, subscriber_db, subscription_type
    FROM dbo.MSdistribution_agents ORDER BY publisher_database_id;
    

    Check whether ids 1, 2, 4, 7, 8 still appear. If they do, those leftover rows are what pin the Dec-2024 low-water mark.

    Was this answer helpful?


  2. Deepesh Dhake 1,165 Reputation points
    2026-07-05T02:53:46.6933333+00:00

    sp_MSdistribution_cleanup deletes based on delivery status combined with retention, not age alone. It won't purge transactions that are still undelivered or still referenced by a subscription, no matter how low you set max_distretention. So the rows being deleted are newer, delivered ones. The oldest transactions are stuck because something still needs them or points to them. Lowering retention further won't move the low-water mark if the blocker is delivery/reference-based rather than age-based.

    You can try running these queries:

    USE distribution

    GO

    -- Oldest transactions still present

    SELECT MIN(entry_time), MAX(entry_time), COUNT(*)

    FROM MSrepl_transactions;

    -- Per-agent delivery progress — find agents that are dead or lagging

    SELECT da.id, da.publisher_db, da.publication, da.subscriber_db,

    MAX(dh.time) AS last_delivery

    FROM MSdistribution_agents da

    LEFT JOIN MSdistribution_history dh ON dh.agent_id = da.id

    GROUP BY da.id, da.publisher_db, da.publication, da.subscriber_db

    ORDER BY last_delivery;

    -- Orphaned agents whose publication no longer exists

    SELECT * FROM MSdistribution_a gents da

    WHERE NOT EXISTS (

    SELECT 1 FROM MSpublications p WHERE p.publication = da.publication

    );

    GO

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.