giip
SES Proposal
SQL Server専門家レビュー必須レプリケーションログファイル性能障害対応

Why MSrepl_commands Keeps Growing in SQL Server, and How to Check for Replication Lag

公開日 2026-08-13 · 更新日 2026-08-13 · 最終検証日 2026-08-13

結論

There are two broad causes of `MSrepl_commands` continuously growing: (a) the distribution agent is failing to apply commands to the subscriber, or (b) the cleanup job is not running, or the retention period is too long. You can isolate which by checking the agent's last activity time in `MSdistribution_history` and pulling the pending command count with `sp_replmonitorsubscriptionpendingcmds`.

この文書の適用条件

対象製品SQL Server (transactional replication configuration)
確認バージョンSQL Server 2008 and later (details depend on the distributor configuration — verify)
適用環境On-premises, EC2, Azure (Amazon RDS has restrictions on replication configuration — verify)
必要権限Read permission on the distribution database. `sp_replmonitorsubscriptionpendingcmds` requires the replmonitor role or sysadmin. Changing the retention period requires sysadmin
実行影響The read-only commands make no changes. Changing the retention period and reinitializing replication affect the configuration
再起動Not required
最終検証日2026-08-13

そのまま実行できるコマンド

Distribution agent's last activity time and distribution latency参照のみ
対象
SQL Server 2008 and later (distributor)
権限
Read permission on the distribution database
変更作業
None (read-only)
Production実行
Safe to run
-- 対象: SQL Server 2008 以降(ディストリビューター)
-- 権限: 配布データベースへの参照権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
USE [distribution];
GO
SELECT
    da.id                      AS agent_id,
    da.name                    AS agent_name,
    da.publisher_db,
    da.publication,
    da.subscriber_db,
    MAX(dh.time)               AS last_history_time,
    MAX(dh.delivered_commands) AS last_delivered_commands,
    MAX(dh.delivery_latency)   AS last_delivery_latency_ms
FROM dbo.MSdistribution_agents AS da
LEFT JOIN dbo.MSdistribution_history AS dh
       ON da.id = dh.agent_id
GROUP BY da.id, da.name, da.publisher_db, da.publication, da.subscriber_db
ORDER BY last_history_time ASC;

An agent whose `last_history_time` is far from the current time is either not running, or running but failing to write history. The agent at the top (oldest) is your investigation target.

Distribution agent's recent run results and error messages参照のみ
対象
SQL Server 2008 and later (distributor)
権限
Read permission on the distribution database
変更作業
None (read-only)
Production実行
Safe to run
-- 対象: SQL Server 2008 以降(ディストリビューター)
-- 権限: 配布データベースへの参照権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
USE [distribution];
GO
SELECT TOP (50)
    dh.agent_id,
    da.name                    AS agent_name,
    dh.runstatus,              -- 1:開始 2:成功 3:実行中 4:アイドル 5:再試行 6:失敗
    dh.start_time,
    dh.time,
    dh.duration,
    dh.delivered_transactions,
    dh.delivered_commands,
    dh.delivery_rate,
    dh.delivery_latency,
    dh.comments
FROM dbo.MSdistribution_history AS dh
INNER JOIN dbo.MSdistribution_agents AS da
        ON dh.agent_id = da.id
ORDER BY dh.time DESC;

If `runstatus = 6` (failed) or `runstatus = 5` (retrying) persists, `comments` will contain the error detail. If there is a command that cannot be applied, distribution stalls there and `MSrepl_commands` stops shrinking.

Get the pending command count (per subscription)参照のみ
対象
SQL Server 2008 and later (distributor)
権限
replmonitor database role or sysadmin
変更作業
None (read-only)
Production実行
Safe to run
-- 対象: SQL Server 2008 以降(ディストリビューター)
-- 権限: replmonitor データベースロール または sysadmin
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
EXEC distribution.dbo.sp_replmonitorsubscriptionpendingcmds
     @publisher         = N'LEGACY-SQL01',
     @publisher_db      = N'SampleDB',
     @publication       = N'SamplePublication',
     @subscriber        = N'LEGACY-SQL01',
     @subscriber_db     = N'SampleDB',
     @subscription_type = 0;   -- 0: プッシュ / 1: プル

This returns the pending command count (pendingcmdcount) and an estimated processing time. If this value keeps growing, the cause is that application to the subscriber is falling behind (case (a)). If this value is small while `MSrepl_commands` is large, suspect the cleanup side instead (case (b)).

Command and transaction counts in the distribution database
対象
SQL Server 2008 and later (distributor)
権限
Read permission on the distribution database
変更作業
None (read-only, but involves a full scan)
Production実行
Safe to run, but can take a long time on a large distribution database
-- 対象: SQL Server 2008 以降(ディストリビューター)
-- 権限: 配布データベースへの参照権限
-- 変更作業: なし(参照のみ。ただし全件スキャンを伴う)
-- Production 実行: 可能。ただし件数が多いと実行時間が長くなるため負荷の低い時間帯を選ぶこと
USE [distribution];
GO
-- トランザクション側(entry_time で保持範囲が分かる)
SELECT
    t.publisher_database_id,
    COUNT(*)          AS transaction_count,
    MIN(t.entry_time) AS oldest_entry_time,
    MAX(t.entry_time) AS newest_entry_time
FROM dbo.MSrepl_transactions AS t
GROUP BY t.publisher_database_id;

-- コマンド側
SELECT
    c.publisher_database_id,
    COUNT(*) AS command_count
FROM dbo.MSrepl_commands AS c
GROUP BY c.publisher_database_id;

`MSrepl_commands` can have an extremely large number of rows, so `COUNT(*)` becomes a full scan. It is read-only but consumes execution time and I/O, so pick a low-load time window. If `oldest_entry_time` is clearly older than the retention period (default 72 hours), cleanup is not running.

Execution history of the distribution cleanup job参照のみ
対象
SQL Server 2008 and later (distributor)
権限
Read permission on msdb
変更作業
None (read-only)
Production実行
Safe to run
-- 対象: SQL Server 2008 以降(ディストリビューター)
-- 権限: msdb への参照権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT TOP (30)
    j.name        AS job_name,
    j.enabled,
    h.run_date,
    h.run_time,
    h.run_duration,
    h.run_status, -- 0:失敗 1:成功 2:再試行 3:取消 4:実行中
    h.message
FROM msdb.dbo.sysjobs AS j
LEFT JOIN msdb.dbo.sysjobhistory AS h
       ON j.job_id = h.job_id
      AND h.step_id = 0
WHERE j.name LIKE 'Distribution clean up%'
ORDER BY h.run_date DESC, h.run_time DESC;

The default job name is `Distribution clean up: distribution`. If `enabled = 0` or `run_status = 0` (failure) persists, distributed commands are not being deleted and `MSrepl_commands` keeps growing.

Check the distribution database's retention settings参照のみ
対象
SQL Server 2008 and later (distributor)
権限
sysadmin or db_owner on the distribution database
変更作業
None (read-only)
Production実行
Safe to run
-- 対象: SQL Server 2008 以降(ディストリビューター)
-- 権限: sysadmin または配布データベースの db_owner
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
EXEC sp_helpdistributiondb @database = N'distribution';

This returns `min_distretention` (minimum retention), `max_distretention` (maximum retention, default 72 hours), and `history_retention` (history retention, default 48 hours). The longer the retention period is set, the longer distributed commands stick around.

Check the content of a specific command (expensive on large databases)
対象
SQL Server 2008 and later (distributor)
権限
sysadmin or db_owner on the distribution database
変更作業
None (read-only, but can run for a long time on a large distribution DB)
Production実行
Not recommended — narrow the range and limit it to a low-load window
-- 対象: SQL Server 2008 以降(ディストリビューター)
-- 権限: sysadmin または配布データベースの db_owner
-- 変更作業: なし(参照のみ。ただし高コスト)
-- Production 実行: 推奨しない。xact_seqno の範囲を必ず絞ること
EXEC distribution.dbo.sp_browsereplcmds
     @xact_seqno_start      = '0x00000000000000000000',
     @xact_seqno_end        = '0x00000000000000000000',
     @publisher_database_id = 1;

`sp_browsereplcmds` decodes commands into a readable form, but running it without narrowing the range scans the entire distribution database. On environments with many rows, this runs for a long time and affects distributor-wide performance, so narrow it to just around the `xact_seqno` you identified from `MSdistribution_history`. The seqno values above are illustrative placeholders for the syntax.

Change the retention period (a configuration change requiring impact review)
対象
SQL Server 2008 and later (distributor)
権限
sysadmin
変更作業
Yes (changes the distribution database's retention policy)
Production実行
Can be run, but shortening it risks deleting pending commands
-- 対象: SQL Server 2008 以降(ディストリビューター)
-- 権限: sysadmin
-- 変更作業: あり(配布データベースの保持ポリシー変更)
-- Production 実行: 可能。ただし短縮は未配布コマンド削除のリスクを伴う
-- 下の値は例示。現在の配布遅延を踏まえて決めること
EXEC sp_changedistributiondb
     @database = N'distribution',
     @property = N'max_distretention',
     @value    = 72;

EXEC sp_changedistributiondb
     @database = N'distribution',
     @property = N'history_retention',
     @value    = 48;

Shortening the retention period increases the amount cleanup can remove, but if a command that a subscriber has not yet received gets deleted, that subscription will require reinitialization. Keep the value comfortably longer than the current maximum distribution latency. The numbers here are illustrative, not recommendations.

Reinitialize a subscription (last resort — requires expert review)専門家レビュー必須
対象
SQL Server 2008 and later (run on the publication database on the publisher side)
権限
sysadmin, or db_owner on the publication database
変更作業
Yes (discards pending commands and requests a resync from a snapshot)
Production実行
Not allowed. Requires an impact assessment equivalent to a business outage and a finalized execution plan first
-- 対象: SQL Server 2008 以降(パブリッシャー側のパブリケーションDBで実行)
-- 権限: sysadmin または パブリケーションDBの db_owner
-- 変更作業: あり(滞留コマンドを破棄し、スナップショットからの再同期を要求)
-- Production 実行: 不可。影響評価と実施計画を確定させ、承認を得てから実施すること
USE [SampleDB];
GO
EXEC sp_reinitsubscription
     @publication    = N'SamplePublication',
     @subscriber     = N'LEGACY-SQL01',
     @destination_db = N'SampleDB';

Requesting reinitialization leaves the target subscriber's data inconsistent until the next snapshot is applied. Generating and applying a snapshot takes time and I/O proportional to the data volume. First consider whether the underlying cause of the backlog (an application error, stalled cleanup) can be resolved instead, and treat this as the last resort if it cannot.

結果の読み方

意味確認するポイント
last_history_timeTime the distribution agent last wrote to historyIf far from the current time, the agent is not running
runstatusAgent run state (2: succeeded, 5: retrying, 6: failed, etc.)If 5 or 6 persists, check the error detail in `comments`
delivery_latencyDistribution latencyA continuous increase means application on the subscriber side cannot keep up
commentsAgent's messageContains the body of an application error — often the direct cause of a stall
pendingcmdcountPending command count (`sp_replmonitorsubscriptionpendingcmds`)A large increase points to the distribution side; small while `MSrepl_commands` is large points to the cleanup side
oldest_entry_timeOldest transaction time remaining in the distribution databaseIf it greatly exceeds the retention period, cleanup is not running
command_countRow count of `MSrepl_commands`Take this over time and watch for a continuing increase — a single reading cannot be judged
run_status (cleanup job)Job execution resultIf 0 (failure) persists, check `message` for the cause
max_distretentionMaximum retention time for the distribution database (default 72 hours)Whether it is set too long — but don't set it shorter than the distribution latency

こういう状況で使います

  • The distribution database keeps growing in size and is squeezing storage
  • Data on the subscriber side has not been updated since a certain point in time
  • The transaction log on the publisher side is not being released, and `log_reuse_wait_desc` stays at REPLICATION
  • Distribution latency in Replication Monitor keeps increasing
  • Snapshot application never finishes, or fails partway through

考えられる原因(可能性の高い順)

  1. 01

    The distribution agent cannot apply commands

    This is the most common cause. If application fails due to a constraint violation, a missing target row, insufficient permissions, or a dropped connection on the subscriber side, distribution stalls there and subsequent commands pile up. The error is recorded in the `comments` column of `MSdistribution_history`.

  2. 02

    The cleanup job is not running

    If the `Distribution clean up: distribution` job is disabled, or keeps failing, already-distributed commands are not deleted and remain. The table keeps growing even if the agent itself is healthy.

  3. 03

    The retention period is set too long

    A large `max_distretention` keeps distributed commands around for a long time. Sometimes this is intentionally set long as a safety margin, so judge whether the setting is appropriate together with operational requirements.

  4. 04

    The subscriber has been down for a long time

    If the subscriber-side server is down or the network is disconnected, the corresponding commands back up in the distribution database. Since they are all delivered at once upon recovery, you need to account for the capacity needed during that window.

  5. 05

    A large update happened all at once

    A bulk delete or bulk update generates one command per row. Updating millions of rows in a single operation grows `MSrepl_commands` proportionally. Splitting into batches smooths this out.

  6. 06

    The same data is being distributed through multiple publications

    If the same table is included in multiple publications, commands are generated per publication. Check for configuration duplication (this depends on the configuration, so it is a hypothesis that needs verifying on the target environment).

確認手順

  1. 1

    Check the distribution agent's last activity time

    参照のみ

    Join `MSdistribution_agents` with `MSdistribution_history` to identify agents with an old `last_history_time`.

  2. 2

    Check recent run results and errors

    参照のみ

    Use `runstatus` and `comments` to see whether it is stalled on an application error.

  3. 3

    Get the pending command count

    参照のみ

    Use `sp_replmonitorsubscriptionpendingcmds` to isolate whether the cause is on the distribution side or the cleanup side.

  4. 4

    Check the cleanup job's history

    参照のみ

    Check whether the job is enabled and has succeeded recently, in `msdb`.

  5. 5

    Cross-check the retention period against the oldest data timestamp

    参照のみ

    Compare `max_distretention` from `sp_helpdistributiondb` against `oldest_entry_time` in `MSrepl_transactions`.

  6. 6

    Get the count trend over time

    A single `COUNT(*)` cannot show a growth trend. Sample it multiple times with a gap to confirm whether it keeps growing.

対応方法

すぐに実施できる低リスクの対応

  • Resolve the distribution agent's error

    Resolve whatever error appears in `comments` (constraint violation, missing row, permissions, connection) and resume the agent. Once the backlog clears, the command count starts dropping.

  • Enable and re-run the cleanup job

    If the job is disabled or failing, check the cause and enable it. If the backlog is large, the first cleanup pass can take a while.

  • Free up space in the distribution database

    If writes are failing due to exhausted capacity, free up space first, then move on to addressing the root cause.

事前検討が必要な変更

  • Align the retention period with actual operations

    Adjust `max_distretention` and `history_retention` to a value comfortably longer than the actual maximum distribution latency, without being longer than necessary. Shortening it too much deletes pending commands.

  • Split bulk updates into batches

    Running large updates in batches reduces the peak in command generation.

  • Add distribution latency and backlog size to your monitoring

    参照のみ

    Periodically pull `pendingcmdcount` and the distribution agent's `last_history_time`, and alert on a threshold crossing. This catches the problem before it manifests as exhausted capacity.

  • Revisit the distribution database's placement and sizing

    Review the distribution database's file placement, initial size, and autogrowth settings so a backlog does not immediately exhaust capacity.

専門家のレビューが必要な作業

  • Reinitialize the subscription (reapply a snapshot)

    専門家レビュー必須

    This discards the backlog and resyncs from scratch. During reinitialization, the subscriber's data is temporarily inconsistent, and generating and applying the snapshot adds significant load. This assumes an impact assessment and a finalized execution plan.

  • Revisit the replication configuration itself

    専門家レビュー必須

    Splitting publications, narrowing articles, or changing the replication method all affect the overall configuration. This assumes a design review.

!注意事項

  • Shortening the retention period risks deleting commands a subscriber has not yet received. A subscription whose commands get deleted this way will require reinitialization. Keep the value comfortably longer than the current maximum distribution latency.
  • `sp_browsereplcmds`, run without narrowing the range, scans the entire distribution database. On environments with many rows this affects distributor-wide performance, so always specify an `xact_seqno` range.
  • `COUNT(*)` against `MSrepl_commands` is a full scan. It is read-only but consumes execution time and I/O.
  • Reinitializing a subscription involves regenerating and reapplying a snapshot, during which the subscriber's data is inconsistent. This requires confirming business impact and obtaining approval first.
  • `log_reuse_wait_desc = REPLICATION` can occur from either transactional replication or CDC. Do not conclude the cause from just one of them.
  • Amazon RDS for SQL Server has restrictions on replication configuration. Check the target environment for whether a distributor can be placed and which features are available.

バージョン・環境による違い

SQL Server 2008 and laterThe distribution database tables referenced in this article (`MSrepl_commands`, `MSrepl_transactions`, `MSdistribution_agents`, `MSdistribution_history`) and the stored procedures are available.
Distributor configurationWhich server you need to check depends on whether the publisher and distributor are the same instance or separate instances. Understand the configuration before running these checks.
Amazon RDS for SQL ServerWhether replication is available and which roles (publisher / distributor / subscriber) it can play depends on the service specification. Verify on the target environment (verify before relying on this).

これで解決しない場合に確認すること

  • The Log Reader Agent on the publisher side

    If commands are not arriving in the distribution database at all, the cause lies with the Log Reader, not the distribution side. Check its running status.

  • Blocking on the subscriber side

    If application is slow, check whether lock waits are occurring on the subscriber.

  • Index fragmentation in the distribution database

    After a prolonged backlog, the index state on the distribution database side also becomes worth checking.

  • Stability of the network path

    If retries keep repeating, the cause may be the network rather than the database.

この文書の根拠と限界

製品の公式ドキュメントに基づく説明

A general procedure based on the public specifications of the SQL Server transactional replication distribution database schema (`MSrepl_commands`, `MSrepl_transactions`, `MSdistribution_agents`, `MSdistribution_history`) and `sp_replmonitorsubscriptionpendingcmds`, `sp_browsereplcmds`, `sp_helpdistributiondb`, and `sp_changedistributiondb`. Specific retention-period values depend on the environment and are illustrative only. Replication restrictions on Amazon RDS assume verification on the target environment.

よくある質問

Why does MSrepl_commands keep growing?

There are two broad causes: the distribution agent failing to apply commands to the subscriber, or the distribution cleanup job not running so already-distributed commands are never deleted. If the pending command count from `sp_replmonitorsubscriptionpendingcmds` is large, it is the former; if it is small while the table is large, it is the latter.

Can this be run in production?

Checking the distribution agent's state, getting the pending command count, and reading job history are all read-only and can be run in production. `COUNT(*)` on `MSrepl_commands` and `sp_browsereplcmds` are read-only but expensive, so limit them to a time window and a narrow range. Changing the retention period and reinitializing are high-impact operations.

What permissions are required?

Reading the distribution database tables requires read permission on that database. `sp_replmonitorsubscriptionpendingcmds` requires the replmonitor database role or sysadmin; changing the retention period (`sp_changedistributiondb`) requires sysadmin.

Does shortening the retention period fix this?

It increases what cleanup can remove, but if pending commands also get deleted, that subscription will require reinitialization. First resolve the underlying cause of the stall, and only then set a retention period comfortably longer than the actual distribution latency.

How should I interpret the results?

A single count cannot be judged on its own. Combine three signals — whether `last_history_time` is updating, whether `pendingcmdcount` is increasing over time, and whether `oldest_entry_time` exceeds the retention period — to decide whether the problem is on the distribution side or the cleanup side.

Does this work on AWS RDS?

Amazon RDS for SQL Server has restrictions on replication configuration, and which role it can play also depends on the service specification. Verify on the target environment, including whether a distributor can be placed there.

この文書がカバーする質問

  • Checking Snapshot Replication lag
  • I want to know why the distribution database keeps growing in size
  • I want to isolate why data is not reaching a subscriber

リスク表示の意味

  • 参照のみデータと設定を変更しません。
  • 影響は限定的ですが、権限と負荷の確認が必要です。
  • 性能・ロック・コストに影響する可能性があります。
  • 障害・データ損失・復旧作業が発生する可能性があります。
  • 専門家レビュー必須本番適用前に別途レビューが必須です。

GIIPの対応範囲

A replication backlog stays hidden until the distribution database runs out of capacity, or until someone on the subscriber side notices the data looks stale. At GIIP, we periodically pull the distribution agent's last activity time and the pending command count, and notify the person in charge once the increase persists for a set duration. Operations tied directly to data consistency and business outages, like reinitialization, are excluded from automatic execution — detection, cause isolation, and scoping the impact are automated, but the decision to act remains human.

執筆・技術検証

GIIP プロダクション運用チーム

大規模Webサービス、SQL Server、Oracle、AWS、Azureの設計・移行・運用に約30年従事。x12largeクラスのAWS RDS for SQL Server環境12セット、約12万テーブルのOracle環境、約3TBのTiDBからAurora MySQLへの移行を経験。現在も複数のクラウドデータベースと約30のWebサービスを、AIエージェントと人間の専門家が継続的に監視・運用しています。

関連するナレッジ

関連サービス

Request help isolating replication lag

同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。

Request help isolating replication lag

ナレッジベース一覧へ