diff --git a/include/opendht/dht.h b/include/opendht/dht.h
index df7ef24588d7a13e7a9f7c66d6671a451f7a6e37..a79619e830489923353275f158ec2c6223959560 100644
--- a/include/opendht/dht.h
+++ b/include/opendht/dht.h
@@ -114,7 +114,7 @@ public:
 
     void addBootstrap(const std::string& host, const std::string& service) override {
         bootstrap_nodes.emplace_back(host, service);
-        onDisconnected();
+        startBootstrap();
     }
 
     void clearBootstrap() override {
@@ -356,6 +356,8 @@ private:
 
     static constexpr duration REANNOUNCE_MARGIN {std::chrono::seconds(10)};
 
+    static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
+
     static constexpr size_t TOKEN_SIZE {32};
 
     // internal structures
@@ -393,7 +395,7 @@ private:
     Kad dht6 {};
 
     std::vector<std::pair<std::string,std::string>> bootstrap_nodes {};
-    std::chrono::steady_clock::duration bootstrap_period {std::chrono::seconds(10)};
+    std::chrono::steady_clock::duration bootstrap_period {BOOTSTRAP_PERIOD};
     Sp<Scheduler::Job> bootstrapJob {};
 
     std::map<InfoHash, Storage> store;
@@ -480,6 +482,9 @@ private:
     void sendCachedPing(Bucket& b);
     bool bucketMaintenance(RoutingTable&);
     void dumpBucket(const Bucket& b, std::ostream& out) const;
+    void bootstrap();
+    void startBootstrap();
+    void stopBootstrap();
 
     // Nodes
     void onNewNode(const Sp<Node>& node, int confirm);
@@ -487,7 +492,6 @@ private:
     bool trySearchInsert(const Sp<Node>& node);
 
     // Searches
-
     inline SearchMap& searches(sa_family_t af) { return dht(af).searches; }
     inline const SearchMap& searches(sa_family_t af) const { return dht(af).searches; }
 
diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h
index 5618d4db0e6631c783f48cea81a3cd4702473694..a55d4b8ec9cc34d5c8598bdd1ff2532cfff7ce5d 100644
--- a/include/opendht/dhtrunner.h
+++ b/include/opendht/dhtrunner.h
@@ -456,8 +456,6 @@ public:
     void forwardAllMessages(bool forward);
 
 private:
-    static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
-
     enum class State {
         Idle,
         Running,
diff --git a/src/dht.cpp b/src/dht.cpp
index 5f054fc34181248af9c95ed973b46a96efb3c72d..ff4abcbd84f18b52db5b5c4930122266abd25e30 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -38,6 +38,7 @@ using namespace std::placeholders;
 
 constexpr std::chrono::minutes Dht::MAX_STORAGE_MAINTENANCE_EXPIRE_TIME;
 constexpr std::chrono::minutes Dht::SEARCH_EXPIRE_TIME;
+constexpr std::chrono::seconds Dht::BOOTSTRAP_PERIOD;
 constexpr duration Dht::LISTEN_EXPIRE_TIME;
 constexpr duration Dht::LISTEN_EXPIRE_TIME_PUBLIC;
 constexpr duration Dht::REANNOUNCE_MARGIN;
@@ -51,9 +52,9 @@ Dht::updateStatus(sa_family_t af)
     d.status = d.getStatus(scheduler.time());
     if (d.status != old) {
         auto& other = dht(af == AF_INET ? AF_INET6 : AF_INET);
-        if (other.status == NodeStatus::Disconnected && d.status == NodeStatus::Disconnected)
+        if (other.status == NodeStatus::Disconnected && d.status == NodeStatus::Disconnected) {
             onDisconnected();
-        else if (other.status == NodeStatus::Connected || d.status == NodeStatus::Connected) {
+        } else if (other.status == NodeStatus::Connected || d.status == NodeStatus::Connected) {
             onConnected();
         }
     }
@@ -2018,11 +2019,7 @@ Dht::expire()
 void
 Dht::onConnected()
 {
-    if (bootstrapJob) {
-        bootstrapJob->cancel();
-        bootstrapJob.reset();
-    }
-    bootstrap_period = std::chrono::seconds(10);
+    stopBootstrap();
     auto callbacks = std::move(onConnectCallbacks_);
     while (not callbacks.empty()) {
         callbacks.front()();
@@ -2032,6 +2029,13 @@ Dht::onConnected()
 
 void
 Dht::onDisconnected()
+{
+    if (not bootstrapJob)
+        bootstrap();
+}
+
+void
+Dht::bootstrap()
 {
     if (dht4.status != NodeStatus::Disconnected || dht6.status != NodeStatus::Disconnected)
         return;
@@ -2052,10 +2056,27 @@ Dht::onDisconnected()
     }
     if (bootstrapJob)
         bootstrapJob->cancel();
-    bootstrapJob = scheduler.add(scheduler.time() + bootstrap_period, std::bind(&Dht::onDisconnected, this));
+    bootstrapJob = scheduler.add(scheduler.time() + bootstrap_period, std::bind(&Dht::bootstrap, this));
     bootstrap_period *= 2;
 }
 
+void
+Dht::startBootstrap()
+{
+    stopBootstrap();
+    bootstrapJob = scheduler.add(scheduler.time(), std::bind(&Dht::bootstrap, this));
+}
+
+void
+Dht::stopBootstrap()
+{
+    if (bootstrapJob) {
+        bootstrapJob->cancel();
+        bootstrapJob.reset();
+    }
+    bootstrap_period = BOOTSTRAP_PERIOD;
+}
+
 void
 Dht::confirmNodes()
 {
diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp
index 51468ca35ee6dede390fd6852f95bbdce1ae79d0..99e6bd075a5aac97eb38012cf8d8481b070727ea 100644
--- a/src/dhtrunner.cpp
+++ b/src/dhtrunner.cpp
@@ -36,7 +36,6 @@
 
 namespace dht {
 
-constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD;
 static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht";
 
 struct DhtRunner::Listener {