diff --git a/src/net_processing.cpp b/src/net_processing.cpp
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -607,6 +607,9 @@
         m_headers_sync PT_GUARDED_BY(m_headers_sync_mutex)
             GUARDED_BY(m_headers_sync_mutex){};
 
+    /** Whether we've sent our peer a sendheaders message. **/
+    std::atomic<bool> m_sent_sendheaders{false};
+
     explicit Peer(NodeId id, ServiceFlags our_services)
         : m_id(id), m_our_services{our_services},
           m_proof_relay(isAvalancheEnabled(gArgs)
@@ -1030,6 +1033,12 @@
     void MaybeSendAddr(CNode &node, Peer &peer,
                        std::chrono::microseconds current_time);
 
+    /**
+     * Send a single `sendheaders` message, after we have completed headers
+     * sync with a peer.
+     */
+    void MaybeSendSendHeaders(CNode &node, Peer &peer);
+
     /** Send `feefilter` message. */
     void MaybeSendFeefilter(CNode &node, Peer &peer,
                             std::chrono::microseconds current_time);
@@ -4502,15 +4511,6 @@
                 pfrom.ConnectionTypeAsString());
         }
 
-        if (pfrom.GetCommonVersion() >= SENDHEADERS_VERSION) {
-            // Tell our peer we prefer to receive headers rather than inv's
-            // We send this to non-NODE NETWORK peers as well, because even
-            // non-NODE NETWORK peers can announce blocks (such as pruning
-            // nodes)
-            m_connman.PushMessage(&pfrom,
-                                  msgMaker.Make(NetMsgType::SENDHEADERS));
-        }
-
         if (pfrom.GetCommonVersion() >= SHORT_IDS_BLOCKS_VERSION) {
             // Tell our peer we are willing to provide version 1
             // cmpctblocks. However, we do not request new block announcements
@@ -7234,6 +7234,28 @@
     }
 }
 
+void PeerManagerImpl::MaybeSendSendHeaders(CNode &node, Peer &peer) {
+    // Delay sending SENDHEADERS (BIP 130) until we're done with an
+    // initial-headers-sync with this peer. Receiving headers announcements for
+    // new blocks while trying to sync their headers chain is problematic,
+    // because of the state tracking done.
+    if (!peer.m_sent_sendheaders &&
+        node.GetCommonVersion() >= SENDHEADERS_VERSION) {
+        LOCK(cs_main);
+        CNodeState &state = *State(node.GetId());
+        if (state.pindexBestKnownBlock != nullptr &&
+            state.pindexBestKnownBlock->nChainWork > nMinimumChainWork) {
+            // Tell our peer we prefer to receive headers rather than inv's
+            // We send this to non-NODE NETWORK peers as well, because even
+            // non-NODE NETWORK peers can announce blocks (such as pruning
+            // nodes)
+            m_connman.PushMessage(&node, CNetMsgMaker(node.GetCommonVersion())
+                                             .Make(NetMsgType::SENDHEADERS));
+            peer.m_sent_sendheaders = true;
+        }
+    }
+}
+
 void PeerManagerImpl::MaybeSendFeefilter(
     CNode &pto, Peer &peer, std::chrono::microseconds current_time) {
     if (m_ignore_incoming_txs) {
@@ -7379,6 +7401,8 @@
 
     MaybeSendAddr(*pto, *peer, current_time);
 
+    MaybeSendSendHeaders(*pto, *peer);
+
     {
         LOCK(cs_main);