diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs
index 80955ca380..5cf80df6aa 100644
--- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs
+++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs
@@ -1,7 +1,9 @@
 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
 // See the LICENCE file in the repository root for full licence text.
 
+using NUnit.Framework;
 using osu.Game.Screens.Multi.Components;
+using osu.Game.Users;
 
 namespace osu.Game.Tests.Visual.RealtimeMultiplayer
 {
@@ -15,6 +17,28 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
             AddUntilStep("wait for loaded", () => multi.IsLoaded);
         }
 
+        [Test]
+        public void TestOneUserJoinedMultipleTimes()
+        {
+            var user = new User { Id = 33 };
+
+            AddRepeatStep("add user multiple times", () => Client.AddUser(user), 3);
+
+            AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2);
+        }
+
+        [Test]
+        public void TestOneUserLeftMultipleTimes()
+        {
+            var user = new User { Id = 44 };
+
+            AddStep("add user", () => Client.AddUser(user));
+            AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2);
+
+            AddRepeatStep("remove user multiple times", () => Client.RemoveUser(user), 3);
+            AddAssert("room has 1 user", () => Client.Room?.Users.Count == 1);
+        }
+
         private class TestRealtimeMultiplayer : Screens.Multi.RealtimeMultiplayer.RealtimeMultiplayer
         {
             protected override RoomManager CreateRoomManager() => new TestRealtimeRoomManager();
diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs
index b7cd81fb32..e9d3ddb32d 100644
--- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs
+++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs
@@ -55,8 +55,6 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
                     }
                 }
             };
-
-            Client.AddUser(API.LocalUser.Value);
         });
 
         [Test]
diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs
index dc999ee2be..9149bdcba3 100644
--- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs
+++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs
@@ -226,6 +226,10 @@ namespace osu.Game.Online.RealtimeMultiplayer
                 if (Room == null)
                     return;
 
+                // for sanity, ensure that there can be no duplicate users in the room user list.
+                if (Room.Users.Any(existing => existing.UserID == user.UserID))
+                    return;
+
                 Room.Users.Add(user);
 
                 RoomChanged?.Invoke();
diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs
index de52633c88..52047016e2 100644
--- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs
+++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
         public void RemoveUser(User user)
         {
             Debug.Assert(Room != null);
-            ((IMultiplayerClient)this).UserLeft(Room.Users.Single(u => u.User == user));
+            ((IMultiplayerClient)this).UserLeft(new MultiplayerRoomUser(user.Id));
 
             Schedule(() =>
             {