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 |
そのまま実行できるコマンド
- 対象
- 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.
- 対象
- 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.
- 対象
- 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)).
- 対象
- 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.
- 対象
- 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.
- 対象
- 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.
- 対象
- 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.
- 対象
- 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.
- 対象
- 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_time | Time the distribution agent last wrote to history | If far from the current time, the agent is not running |
| runstatus | Agent run state (2: succeeded, 5: retrying, 6: failed, etc.) | If 5 or 6 persists, check the error detail in `comments` |
| delivery_latency | Distribution latency | A continuous increase means application on the subscriber side cannot keep up |
| comments | Agent's message | Contains the body of an application error — often the direct cause of a stall |
| pendingcmdcount | Pending 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_time | Oldest transaction time remaining in the distribution database | If it greatly exceeds the retention period, cleanup is not running |
| command_count | Row 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 result | If 0 (failure) persists, check `message` for the cause |
| max_distretention | Maximum 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
考えられる原因(可能性の高い順)
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`.
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.
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.
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.
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.
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
Check the distribution agent's last activity time
参照のみJoin `MSdistribution_agents` with `MSdistribution_history` to identify agents with an old `last_history_time`.
- 2
Check recent run results and errors
参照のみUse `runstatus` and `comments` to see whether it is stalled on an application error.
- 3
Get the pending command count
参照のみUse `sp_replmonitorsubscriptionpendingcmds` to isolate whether the cause is on the distribution side or the cleanup side.
- 4
Check the cleanup job's history
参照のみCheck whether the job is enabled and has succeeded recently, in `msdb`.
- 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
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.
バージョン・環境による違い
これで解決しない場合に確認すること
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エージェントと人間の専門家が継続的に監視・運用しています。
How to Check Whether CDC Log Scanning Has Stopped in SQL Server
A procedure for checking whether CDC's log scan is progressing, using sys.dm_cdc_log_scan_sessions, cdc.lsn_time_mapping, and the state of the capture job.
sql-serverHow to Check Transaction Log Usage on RDS for SQL Server
A read-only procedure that checks log usage with DBCC SQLPERF(LOGSPACE) and sys.dm_db_log_space_usage, and isolates the reason it is not being released using log_reuse_wait_desc.
sql-serverSQL to Check for Long-Running Open Transactions in SQL Server
A procedure using the sys.dm_tran_active_transactions family of DMVs to identify abandoned transactions, including start time, session, and the last SQL statement executed.
monitoringWhat to Configure When Monitoring Servers and Databases 24/7
A checklist, organized by layer, of what to monitor, how to think about thresholds, the escalation structure, and why synthetic monitoring is necessary when designing 24/7 monitoring.
関連サービス
Request help isolating replication lag
同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。
Request help isolating replication lag