diff --git a/docs/clustering.md b/docs/clustering.md
index 04d6675951c157e6548f3de9a50a0257a78533e3..cb313212e4ea3e1c09b60b095211128d14f18491 100644
--- a/docs/clustering.md
+++ b/docs/clustering.md
@@ -23,7 +23,7 @@ picodata run --instance-id iN --listen iN --peer i1,i2
 ![main.rs](clustering_curves.svg "main.rs control flow")
 
 Красным показан родительский процесс, который запущен на всём протяжении жизненного цикла инстанса. Вся логика поиска лидера Raft-группы и присоединения к ней происходит в дочернем процессе (голубой цвет). При сбросе состояния инстанса и rebootstrap происходит повторная инициализация форка (сиреневый цвет).
- 
+
 Данная схема наиболее полно отражает логику кода в файле `main.rs`. Ниже описаны детали выполнения каждого этапа и соответствующей программной функции.
 
 ### fn main()
@@ -32,8 +32,7 @@ picodata run --instance-id iN --listen iN --peer i1,i2
 
 ### fn start_discover()
 
-Дочерний процесс начинает своё существование с запуска модуля `box.cfg()` и вызова функции `start_discover`. Возможно, что при этом из постоянно хранимых данных будет ясно, что bootstrap данного инстанса уже был произведён ранее и что Raft уже знает о вхождении этого инстанса в кластер - в таком случае никакого discovery не будет, инстанс сразу перейдёт к этапу `postjoin()`. Однако, если это новый инстанс, то алгоритм discovery выдаст ему флаг `i_am_bootstrap_leader == false` и сообщит адрес лидера Raft-группы. Сам лидер (единственный с `i_am_bootstrap_leader == true`) выполняет функцию `start_boot` и затем переходит к функции `postjoin()`. Остальные инстансы (уже запущенные и все будущие) сбрасывают своё состояние (этап rebootstrap) и переходят к функции `start_join`.
-
+Дочерний процесс начинает своё существование с запуска модуля `box.cfg()` и вызова функции `start_discover`. Возможно, что при этом из постоянно хранимых данных будет ясно, что bootstrap данного инстанса уже был произведён ранее и что Raft уже знает о вхождении этого инстанса в кластер - в таком случае никакого discovery не будет, инстанс сразу перейдёт к этапу `postjoin()`. В противном случае, если место инстанса в кластере ещё не известно, алгоритм discovery опредяет значение флага `i_am_bootstrap_leader` и адрес лидера Raft-группы. Далее все инстансы сбрасывают своё состояние (этап rebootstrap) чтобы повторно провести инициализацию `box.cfg`, теперь уже с известными параметрами. Сам лидер (единственный с `i_am_bootstrap_leader == true`) выполняет функцию `start_boot`. Остальные инстансы переходят к функции `start_join`.
 
 ### fn start_boot()
 
diff --git a/docs/clustering_curves.svg b/docs/clustering_curves.svg
index 107a7add67fb907180a549fc03ca141531fa3842..69d7454948e1da6f52c89873740918ec5fb85a5b 100644
Binary files a/docs/clustering_curves.svg and b/docs/clustering_curves.svg differ
diff --git a/src/main.rs b/src/main.rs
index 7b5c8bda4149d4d2040133d7f9f23d80bffeb609..bfc8b2d0d57158c7fbc913265d8dd9300c90c1ae 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -162,9 +162,11 @@ fn main() -> ! {
     }
 }
 
+#[allow(clippy::enum_variant_names)]
 #[derive(Debug, Serialize, Deserialize)]
 enum Entrypoint {
     StartDiscover,
+    StartBoot,
     StartJoin { leader_address: String },
 }
 
@@ -172,6 +174,7 @@ impl Entrypoint {
     fn exec(self, args: args::Run, to_supervisor: ipc::Sender<IpcMessage>) {
         match self {
             Self::StartDiscover => start_discover(&args, to_supervisor),
+            Self::StartBoot => start_boot(&args),
             Self::StartJoin { leader_address } => start_join(&args, leader_address),
         }
     }
@@ -351,6 +354,8 @@ fn start_discover(args: &args::Run, to_supervisor: ipc::Sender<IpcMessage>) {
     picolib_setup(args);
     assert!(tarantool::cfg().is_none());
 
+    // Don't try to guess instance and replicaset uuids now,
+    // finally, the box will be rebootstraped after discovery.
     let mut cfg = tarantool::Cfg {
         listen: None,
         read_only: false,
@@ -364,14 +369,6 @@ fn start_discover(args: &args::Run, to_supervisor: ipc::Sender<IpcMessage>) {
     tarantool::set_cfg(&cfg);
 
     traft::Storage::init_schema();
-
-    // исходный discovery::discover() пришлось разбить на две части -
-    // init_global и wait_global. К сожалению, они не могут быть атомарны,
-    // потому что listen порт надо поднимать именно посередине. С неподнятым портом
-    // уходить в кишки discovery::discover() нельзя - на запросы отвечать будет некому.
-    // А если поднять порт до инициализации дискавери, то образуется временно́е окно,
-    // и прилетевший пакет приведёт к панике "discovery error: expected DISCOVERY
-    // to be set on instance startup"
     discovery::init_global(&args.peers);
     init_handlers();
 
@@ -386,7 +383,13 @@ fn start_discover(args: &args::Run, to_supervisor: ipc::Sender<IpcMessage>) {
 
     match role {
         discovery::Role::Leader { .. } => {
-            start_boot(args);
+            let next_entrypoint = Entrypoint::StartBoot {};
+            let msg = IpcMessage {
+                next_entrypoint,
+                drop_db: true,
+            };
+            to_supervisor.send(&msg);
+            std::process::exit(0);
         }
         discovery::Role::NonLeader { leader } => {
             let next_entrypoint = Entrypoint::StartJoin {
@@ -416,6 +419,26 @@ fn start_boot(args: &args::Run) {
     let peer = topology.diff().pop().unwrap();
     let raft_id = peer.raft_id;
 
+    picolib_setup(args);
+    assert!(tarantool::cfg().is_none());
+
+    let cfg = tarantool::Cfg {
+        listen: None,
+        read_only: false,
+        instance_uuid: Some(peer.instance_uuid.clone()),
+        replicaset_uuid: Some(peer.replicaset_uuid.clone()),
+        wal_dir: args.data_dir.clone(),
+        memtx_dir: args.data_dir.clone(),
+        log_level: args.log_level() as u8,
+        ..Default::default()
+    };
+
+    std::fs::create_dir_all(&args.data_dir).unwrap();
+    tarantool::set_cfg(&cfg);
+
+    traft::Storage::init_schema();
+    init_handlers();
+
     start_transaction(|| -> Result<(), Error> {
         let cs = raft::ConfState {
             voters: vec![raft_id],
diff --git a/test/int/test_joining.py b/test/int/test_joining.py
index f2bf7d320bbd84ffc9313217a6d93863131138e4..d153b1974f30684882d4521460bcf5068f50068a 100644
--- a/test/int/test_joining.py
+++ b/test/int/test_joining.py
@@ -78,27 +78,39 @@ def test_request_follower(cluster2: Cluster):
     assert e.value.args == ("ER_PROC_C", "not a leader")
 
 
-def test_instance_uuid(cluster2: Cluster):
+def test_uuids(cluster2: Cluster):
     i1, i2 = cluster2.instances
     i1.assert_raft_status("Leader")
 
-    ret = i1.call(
+    peer_1 = i1.call(
+        ".raft_join",
+        i1.instance_id,
+        None,  # replicaset_id
+        i1.listen,  # address
+        True,  # voter
+    )[0]["peer"]
+    assert peer_1["instance_id"] == i1.instance_id
+    assert peer_1["instance_uuid"] == i1.eval("return box.info.uuid")
+    assert peer_1["replicaset_uuid"] == i1.eval("return box.info.cluster.uuid")
+
+    peer_2 = i1.call(
         ".raft_join",
         i2.instance_id,
         None,  # replicaset_id
         i2.listen,  # address
         True,  # voter
     )[0]["peer"]
-    assert ret["instance_id"] == i2.instance_id
-    assert ret["instance_uuid"] == i2.eval("return box.info.uuid")
+    assert peer_2["instance_id"] == i2.instance_id
+    assert peer_2["instance_uuid"] == i2.eval("return box.info.uuid")
+    assert peer_2["replicaset_uuid"] == i2.eval("return box.info.cluster.uuid")
 
     # Two consequent requests must obtain same raft_id and instance_id
-    ret1 = fake_join(i1, "fake", timeout=1)[0]["peer"]
-    ret2 = fake_join(i1, "fake", timeout=1)[0]["peer"]
-    assert ret1["instance_id"] == "fake"
-    assert ret2["instance_id"] == "fake"
-    assert ret1["raft_id"] == ret2["raft_id"]
-    assert ret1["instance_uuid"] == ret2["instance_uuid"]
+    fake_peer_1 = fake_join(i1, "fake", timeout=1)[0]["peer"]
+    fake_peer_2 = fake_join(i1, "fake", timeout=1)[0]["peer"]
+    assert fake_peer_1["instance_id"] == "fake"
+    assert fake_peer_2["instance_id"] == "fake"
+    assert fake_peer_1["raft_id"] == fake_peer_2["raft_id"]
+    assert fake_peer_1["instance_uuid"] == fake_peer_2["instance_uuid"]
 
 
 def test_discovery(cluster: Cluster):