diff --git a/config/bridge.go b/config/bridge.go
index d263333..8056a24 100644
--- a/config/bridge.go
+++ b/config/bridge.go
@@ -34,6 +34,7 @@ type BridgeConfig struct {
 	DisplaynameTemplate string `yaml:"displayname_template"`
 
 	ConnectionTimeout     int  `yaml:"connection_timeout"`
+	LoginQRRegenCount     int  `yaml:"login_qr_regen_count"`
 	MaxConnectionAttempts int  `yaml:"max_connection_attempts"`
 	ConnectionRetryDelay  int  `yaml:"connection_retry_delay"`
 	ReportConnectionRetry bool `yaml:"report_connection_retry"`
@@ -62,6 +63,7 @@ type BridgeConfig struct {
 
 func (bc *BridgeConfig) setDefaults() {
 	bc.ConnectionTimeout = 20
+	bc.LoginQRRegenCount = 2
 	bc.MaxConnectionAttempts = 3
 	bc.ConnectionRetryDelay = -1
 	bc.ReportConnectionRetry = true
diff --git a/example-config.yaml b/example-config.yaml
index 3947b00..4912846 100644
--- a/example-config.yaml
+++ b/example-config.yaml
@@ -60,6 +60,9 @@ bridge:
 
     # WhatsApp connection timeout in seconds.
     connection_timeout: 20
+    # Number of times to regenerate QR code when logging in.
+    # The regenerated QR code is sent as an edit and essentially multiplies the login timeout (20 seconds)
+    login_qr_regen_count: 2
     # Maximum number of times to retry connecting on connection error.
     max_connection_attempts: 3
     # Number of seconds to wait between connection attempts.
diff --git a/user.go b/user.go
index c7ee645..8a31835 100644
--- a/user.go
+++ b/user.go
@@ -221,11 +221,11 @@ func (user *User) IsLoggedIn() bool {
 	return user.Session != nil || user.Conn != nil
 }
 
-func (user *User) Login(ce *CommandEvent) {
-	qrChan := make(chan string, 2)
-	go func() {
-		code := <-qrChan
-		if code == "error" {
+func (user *User) loginQrChannel(ce *CommandEvent, qrChan <-chan string, eventIDChan chan<- string) {
+	var qrEventID string
+	for code := range qrChan {
+		fmt.Println("qrChan:", code)
+		if code == "stop" {
 			return
 		}
 		qrCode, err := qrcode.Encode(code, qrcode.Low, 256)
@@ -244,24 +244,70 @@ func (user *User) Login(ce *CommandEvent) {
 			return
 		}
 
-		_, err = bot.SendImage(ce.RoomID, string(code), resp.ContentURI)
-		if err != nil {
-			user.log.Errorln("Failed to send QR code to user:", err)
+		if qrEventID == "" {
+			sendResp, err := bot.SendImage(ce.RoomID, code, resp.ContentURI)
+			if err != nil {
+				user.log.Errorln("Failed to send QR code to user:", err)
+				return
+			}
+			qrEventID = sendResp.EventID
+			eventIDChan <- qrEventID
+		} else {
+			_, err = bot.SendMessageEvent(ce.RoomID, mautrix.EventMessage, &mautrix.Content{
+				MsgType: mautrix.MsgImage,
+				Body:    code,
+				URL:     resp.ContentURI,
+				NewContent: &mautrix.Content{
+					MsgType: mautrix.MsgImage,
+					Body:    code,
+					URL:     resp.ContentURI,
+				},
+				RelatesTo: &mautrix.RelatesTo{
+					Type:    mautrix.RelReplace,
+					EventID: qrEventID,
+				},
+			})
+			if err != nil {
+				user.log.Errorln("Failed to send edited QR code to user:", err)
+			}
 		}
-	}()
-	session, err := user.Conn.Login(qrChan)
+	}
+}
+
+func (user *User) Login(ce *CommandEvent) {
+	qrChan := make(chan string, 3)
+	eventIDChan := make(chan string, 1)
+	go user.loginQrChannel(ce, qrChan, eventIDChan)
+	session, err := user.Conn.LoginWithRetry(qrChan, user.bridge.Config.Bridge.LoginQRRegenCount)
+	qrChan <- "stop"
 	if err != nil {
-		qrChan <- "error"
+		var eventID string
+		select {
+		case eventID = <-eventIDChan:
+		default:
+		}
+		reply := mautrix.Content{
+			MsgType: mautrix.MsgText,
+		}
 		if err == whatsapp.ErrAlreadyLoggedIn {
-			ce.Reply("You're already logged in.")
+			reply.Body = "You're already logged in"
 		} else if err == whatsapp.ErrLoginInProgress {
-			ce.Reply("You have a login in progress already.")
-		} else if err.Error() == "qr code scan timed out" {
-			ce.Reply("QR code scan timed out. Please try again.")
+			reply.Body = "You have a login in progress already."
+		} else if err == whatsapp.ErrLoginTimedOut {
+			reply.Body = "QR code scan timed out. Please try again."
 		} else {
 			user.log.Warnln("Failed to log in:", err)
-			ce.Reply("Unknown error while logging in: %v", err)
+			reply.Body = fmt.Sprintf("Unknown error while logging in: %v", err)
 		}
+		msg := reply
+		if eventID != "" {
+			msg.NewContent = &reply
+			msg.RelatesTo = &mautrix.RelatesTo{
+				Type:    mautrix.RelReplace,
+				EventID: eventID,
+			}
+		}
+		_, _ = ce.Bot.SendMessageEvent(ce.RoomID, mautrix.EventMessage, &msg)
 		return
 	}
 	user.Connected = true