diff --git a/Cargo.toml b/Cargo.toml
index 8068eed19b16a102d18cab5c4c07d6250a95b568..61b4441708bea563bbf336b968d2f16a32d0a35b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,6 +13,7 @@ panic = 'abort'
 matrix-sdk = "0.4.1"
 tokio      = { version = "1", features = ["rt", "rt-multi-thread", "sync", "macros"] }
 rust-ini   = "0.17"
-url        = "2.2.2"
+url        = "2.2"
 log        = "0.4"
 log4rs     = "1.0"
+futures    = "0.3"
diff --git a/README.md b/README.md
index 94c16eec6f85df8a28e092efb9c6bb12cdf0c5c1..f94396ae8001d763355d5b1378a0c10c8e803663 100644
--- a/README.md
+++ b/README.md
@@ -10,3 +10,9 @@ toolchain, so a `rustup default nightly` might be needed.
 ## Help
 
 Here are the matrix sdk samples: https://github.com/matrix-org/matrix-rust-sdk/tree/main/crates/matrix-sdk/examples
+
+## TODO
+
+- Auto-join without restarting the bot
+- When joining rooms at start-up, the bot no longer know the name of the rooms,
+  need another start-up to fix...
diff --git a/src/matrix.rs b/src/matrix.rs
index 78f91b08855d4a9e5cc1f03b3ffe3d41fba0e348..307c439ad04c11bd6fae0c09ccd1dd201743d397 100644
--- a/src/matrix.rs
+++ b/src/matrix.rs
@@ -2,17 +2,70 @@ use crate::config::Config;
 use log::{error, info, warn};
 use matrix_sdk::{
     deserialized_responses::EncryptionInfo,
-    room::Room,
+    room::{Invited, Room},
     ruma::{
         events::{
-            room::message::{MessageEventContent, MessageType, TextMessageEventContent},
-            AnyMessageEventContent, SyncMessageEvent,
+            room::{
+                member::MemberEventContent,
+                message::{MessageEventContent, MessageType, TextMessageEventContent},
+            },
+            SyncMessageEvent, SyncStateEvent,
         },
         UserId,
     },
-    Client, Result, RoomInfo, SyncSettings,
+    Client, Result, SyncSettings,
 };
 use std::convert::TryFrom;
+use futures::join;
+use tokio::time::{sleep, Duration};
+
+async fn join_room(room: &Invited) {
+    info!("Autojoining room {}", room.room_id());
+    let mut delay = 2; // seconds
+
+    while let Err(err) = room.accept_invitation().await {
+        // retry autojoin due to synapse sending invites, before the invited
+        // user can join for more information see
+        // https://github.com/matrix-org/synapse/issues/4345
+        error!(
+            "Failed to join room {} ({:?}), retrying in {}s",
+            room.room_id(),
+            err,
+            delay
+        );
+
+        sleep(Duration::from_secs(delay)).await;
+        delay *= 2;
+
+        if delay > 60 {
+            error!("Can't join room {} ({:?})", room.room_id(), err);
+            break;
+        }
+    }
+    info!("Successfully joined room {}", room.room_id());
+}
+
+async fn on_state_member(
+    room_member: SyncStateEvent<MemberEventContent>,
+    client: Client,
+    room: Room,
+) {
+    let room_member_state_key = room_member.state_key;
+    let own_user_id = client.user_id().await.unwrap();
+    if room_member_state_key != own_user_id {
+        error!(
+            "Room member state key {} don't match bot's id {}",
+            room_member_state_key, own_user_id
+        );
+        return;
+    }
+
+    match room {
+        Room::Joined(room) => warn!("Room {} already joined", room.room_id()),
+        Room::Invited(room) => join_room(&room).await,
+        Room::Left(room) => warn!("Leave room {}", room.room_id()),
+    };
+}
 
 async fn on_room_message(
     ev: SyncMessageEvent<MessageEventContent>,
@@ -61,10 +114,17 @@ async fn on_room_message(
     }
 }
 
-fn log_joined_rooms(client: &Client) {
+async fn startup_and_log_rooms(client: &Client) {
     for room in client.joined_rooms() {
         info!("Got joined room: <{}>", room.name().unwrap());
     }
+    for room in client.invited_rooms() {
+        warn!(
+            "Got pending invitation on room <{}>, try to join it",
+            room.name().unwrap()
+        );
+        join_room(&room).await;
+    }
 }
 
 pub async fn connect_and_handle(config: Config) -> Result<()> {
@@ -82,9 +142,11 @@ pub async fn connect_and_handle(config: Config) -> Result<()> {
     info!("Logged as: {}", alice);
 
     client.sync_once(SyncSettings::default()).await?;
-    log_joined_rooms(&client);
 
-    client.register_event_handler(on_room_message).await;
+    let startup_rooms = startup_and_log_rooms(&client);
+    let register_handle_state = client.register_event_handler(on_state_member);
+    let register_handle_message = client.register_event_handler(on_room_message);
+    join!(startup_rooms, register_handle_message, register_handle_state);
 
     info!("Entering sync loop");
     let token = client.sync_token().await.unwrap();