diff --git a/src/net.cpp b/src/net.cpp
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -15,6 +15,7 @@
 #include <consensus/consensus.h>
 #include <crypto/sha256.h>
 #include <netbase.h>
+#include <random.h>
 #include <scheduler.h>
 #include <ui_interface.h>
 #include <util/strencodings.h>
@@ -457,6 +458,10 @@
                   pszDest ? pszDest : "", false, block_relay_only);
     pnode->AddRef();
 
+    // We're making a new connection, harvest entropy from the time (and our
+    // peer count)
+    RandAddEvent((uint32_t)id);
+
     return pnode;
 }
 
@@ -721,8 +726,13 @@
     msg.m_message_size = hdr.nMessageSize;
     msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
 
+    // We just received a message off the wire, harvest entropy from the time
+    // (and the message checksum)
+    RandAddEvent(ReadLE32(hash.begin()));
+
     msg.m_valid_checksum = (memcmp(hash.begin(), hdr.pchChecksum,
                                    CMessageHeader::CHECKSUM_SIZE) == 0);
+
     if (!msg.m_valid_checksum) {
         LogPrint(
             BCLog::NET, "CHECKSUM ERROR (%s, %u bytes), expected %s was %s\n",
@@ -1130,6 +1140,10 @@
         LOCK(cs_vNodes);
         vNodes.push_back(pnode);
     }
+
+    // We received a new connection, harvest entropy from the time (and our peer
+    // count)
+    RandAddEvent((uint32_t)id);
 }
 
 void CConnman::DisconnectNodes() {
diff --git a/src/random.h b/src/random.h
--- a/src/random.h
+++ b/src/random.h
@@ -94,6 +94,14 @@
  */
 void RandAddPeriodic() noexcept;
 
+/**
+ * Gathers entropy from the low bits of the time at which events occur. Should
+ * be called with a uint32_t describing the event at the time an event occurs.
+ *
+ * Thread-safe.
+ */
+void RandAddEvent(const uint32_t event_info) noexcept;
+
 /**
  * Fast randomness source. This is seeded once with secure random data, but
  * is completely deterministic and does not gather more entropy after that.
diff --git a/src/random.cpp b/src/random.cpp
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -10,6 +10,7 @@
 #include <wincrypt.h>
 #endif
 #include <compat/cpuid.h>
+#include <crypto/sha256.h>
 #include <crypto/sha512.h>
 #include <logging.h> // for LogPrintf()
 #include <randomenv.h>
@@ -403,11 +404,43 @@
     uint64_t m_counter GUARDED_BY(m_mutex) = 0;
     bool m_strongly_seeded GUARDED_BY(m_mutex) = false;
 
+    Mutex m_events_mutex;
+    CSHA256 m_events_hasher GUARDED_BY(m_events_mutex);
+
 public:
     RNGState() noexcept { InitHardwareRand(); }
 
     ~RNGState() {}
 
+    void AddEvent(uint32_t event_info) noexcept {
+        LOCK(m_events_mutex);
+
+        m_events_hasher.Write((const uint8_t *)&event_info, sizeof(event_info));
+        // Get the low four bytes of the performance counter. This translates to
+        // roughly the subsecond part.
+        uint32_t perfcounter = (GetPerformanceCounter() & 0xffffffff);
+        m_events_hasher.Write((const uint8_t *)&perfcounter,
+                              sizeof(perfcounter));
+    }
+
+    /**
+     * Feed (the hash of) all events added through AddEvent() to hasher.
+     */
+    void SeedEvents(CSHA512 &hasher) noexcept {
+        // We use only SHA256 for the events hashing to get the ASM speedups we
+        // have for SHA256, since we want it to be fast as network peers may be
+        // able to trigger it repeatedly.
+        LOCK(m_events_mutex);
+
+        uint8_t events_hash[32];
+        m_events_hasher.Finalize(events_hash);
+        hasher.Write(events_hash, 32);
+
+        // Re-initialize the hasher with the finalized state to use later.
+        m_events_hasher.Reset();
+        m_events_hasher.Write(events_hash, 32);
+    }
+
     /**
      * Extract up to 32 bytes of entropy from the RNG state, mixing in new
      * entropy from hasher.
@@ -482,7 +515,7 @@
     SeedTimestamp(hasher);
 }
 
-static void SeedSlow(CSHA512 &hasher) noexcept {
+static void SeedSlow(CSHA512 &hasher, RNGState &rng) noexcept {
     uint8_t buffer[32];
 
     // Everything that the 'fast' seeder includes
@@ -492,6 +525,9 @@
     GetOSRand(buffer);
     hasher.Write(buffer, sizeof(buffer));
 
+    // Add the events hasher into the mix
+    rng.SeedEvents(hasher);
+
     // High-precision timestamp.
     //
     // Note that we also commit to a timestamp in the Fast seeder, so we
@@ -519,6 +555,9 @@
     // High-precision timestamp
     SeedTimestamp(hasher);
 
+    // Add the events hasher into the mix
+    rng.SeedEvents(hasher);
+
     // Dynamic environment data (performance monitoring, ...)
     auto old_size = hasher.Size();
     RandAddDynamicEnv(hasher);
@@ -535,7 +574,7 @@
     SeedHardwareSlow(hasher);
 
     // Everything that the 'slow' seeder includes.
-    SeedSlow(hasher);
+    SeedSlow(hasher, rng);
 
     // Dynamic environment data (performance monitoring, ...)
     auto old_size = hasher.Size();
@@ -556,7 +595,7 @@
     PERIODIC, //!< Called by RandAddPeriodic()
 };
 
-static void ProcRand(uint8_t *out, int num, RNGLevel level) {
+static void ProcRand(uint8_t *out, int num, RNGLevel level) noexcept {
     // Make sure the RNG is initialized first (as all Seed* function possibly
     // need hwrand to be available).
     RNGState &rng = GetRNGState();
@@ -569,7 +608,7 @@
             SeedFast(hasher);
             break;
         case RNGLevel::SLOW:
-            SeedSlow(hasher);
+            SeedSlow(hasher, rng);
             break;
         case RNGLevel::PERIODIC:
             SeedPeriodic(hasher, rng);
@@ -595,6 +634,10 @@
     ProcRand(nullptr, 0, RNGLevel::PERIODIC);
 }
 
+void RandAddEvent(const uint32_t event_info) noexcept {
+    GetRNGState().AddEvent(event_info);
+}
+
 bool g_mock_deterministic_tests{false};
 
 uint64_t GetRand(uint64_t nMax) noexcept {