diff --git a/modules/m_room_bootstrap.cc b/modules/m_room_bootstrap.cc
index 5ad678185..136bfe52d 100644
--- a/modules/m_room_bootstrap.cc
+++ b/modules/m_room_bootstrap.cc
@@ -15,6 +15,7 @@ namespace ircd::m::bootstrap
 
 	static event::id::buf make_join(const string_view &host, const room::id &, const user::id &);
 	static send_join1_response send_join(const string_view &host, const room::id &, const event::id &, const json::object &event);
+	static void broadcast_join(const room &, const event &, const string_view &exclude);
 	static void fetch_keys(const json::array &events);
 	static void eval_lazy_chain(const json::array &auth_chain);
 	static void eval_auth_chain(const json::array &auth_chain);
@@ -259,19 +260,21 @@ try
 		auth_chain.size(),
 	};
 
+	m::bootstrap::fetch_keys(auth_chain);
+
 	if(m::bootstrap::lazychain_enable)
 		m::bootstrap::eval_lazy_chain(auth_chain);
 	else
 		m::bootstrap::eval_auth_chain(auth_chain);
 
 	if(m::bootstrap::backfill_first)
-	{
 		m::bootstrap::backfill(host, room_id, event_id);
-		m::bootstrap::eval_state(state);
-	} else {
-		m::bootstrap::eval_state(state);
+
+	m::bootstrap::fetch_keys(state);
+	m::bootstrap::eval_state(state);
+
+	if(!m::bootstrap::backfill_first)
 		m::bootstrap::backfill(host, room_id, event_id);
-	}
 
 	// After we just received and processed all of this state with only a
 	// recent backfill our system doesn't know if state events which are
@@ -285,6 +288,12 @@ try
 		m::room::head::reset(room)
 	};
 
+	// At this point we have only transmitted the join event to one bootstrap
+	// server. Now that we have processed the state we know of more servers.
+	// They don't know about our join event though, so we conduct a synchronous
+	// broadcast to the room now manually.
+	m::bootstrap::broadcast_join(room, event, host);
+
 	log::info
 	{
 		log, "Joined to %s for %s at %s reset:%zu complete",
@@ -349,6 +358,83 @@ catch(const std::exception &e)
 	};
 }
 
+void
+ircd::m::bootstrap::broadcast_join(const m::room &room,
+                                   const m::event &event,
+                                   const string_view &exclude) //TODO: XX
+{
+	const m::room::origins origins
+	{
+		room
+	};
+
+	log::info
+	{
+		log, "Broadcasting %s to %s estimated servers:%zu",
+		string_view{event.event_id},
+		string_view{room.room_id},
+		origins.count(),
+	};
+
+	const json::value pdu
+	{
+		event.source
+	};
+
+	const vector_view<const json::value> pdus
+	{
+		&pdu, 1
+	};
+
+	const auto txn
+	{
+		m::txn::create(pdus)
+	};
+
+	char idbuf[128];
+	const auto txnid
+	{
+		m::txn::create_id(idbuf, txn)
+	};
+
+	m::feds::opts opts;
+	opts.op = feds::op::send;
+	opts.exclude_myself = true;
+	opts.room_id = room;
+	opts.arg[0] = txnid;
+	opts.arg[1] = txn;
+
+	size_t good(0), fail(0);
+	m::feds::execute(opts, [&event, &good, &fail]
+	(const auto &result)
+	{
+		if(result.eptr)
+			log::derror
+			{
+				log, "Failed to broadcast %s to %s :%s",
+				string_view{event.event_id},
+				result.origin,
+				what(result.eptr),
+			};
+
+		fail += bool(result.eptr);
+		good += !result.eptr;
+		return true;
+	});
+
+	log::info
+	{
+		log, "Broadcast %s to %s good:%zu fail:%zu servers:%zu online:%zu error:%zu",
+		string_view{event.event_id},
+		string_view{room.room_id},
+		good,
+		fail,
+		origins.count(),
+		origins.count_online(),
+		origins.count_error(),
+	};
+}
+
 void
 ircd::m::bootstrap::backfill(const string_view &host,
                              const m::room::id &room_id,
@@ -435,8 +521,6 @@ void
 ircd::m::bootstrap::eval_state(const json::array &state)
 try
 {
-	fetch_keys(state);
-
 	log::info
 	{
 		log, "Evaluating %zu state events...",
@@ -471,8 +555,6 @@ void
 ircd::m::bootstrap::eval_auth_chain(const json::array &auth_chain)
 try
 {
-	fetch_keys(auth_chain);
-
 	log::info
 	{
 		log, "Evaluating %zu authentication events...",