diff --git a/src/citra_qt/multiplayer/message.cpp b/src/citra_qt/multiplayer/message.cpp
index 2cf76256f..2489a6ffd 100644
--- a/src/citra_qt/multiplayer/message.cpp
+++ b/src/citra_qt/multiplayer/message.cpp
@@ -12,8 +12,8 @@ const ConnectionError USERNAME_NOT_VALID(
     QT_TR_NOOP("Username is not valid. Must be 4 to 20 alphanumeric characters."));
 const ConnectionError ROOMNAME_NOT_VALID(
     QT_TR_NOOP("Room name is not valid. Must be 4 to 20 alphanumeric characters."));
-const ConnectionError USERNAME_IN_USE(
-    QT_TR_NOOP("Username is already in use. Please choose another."));
+const ConnectionError USERNAME_NOT_VALID_SERVER(
+    QT_TR_NOOP("Username is already in use or not valid. Please choose another."));
 const ConnectionError IP_ADDRESS_NOT_VALID(QT_TR_NOOP("IP is not a valid IPv4 address."));
 const ConnectionError PORT_NOT_VALID(QT_TR_NOOP("Port must be a number between 0 to 65535."));
 const ConnectionError NO_INTERNET(
diff --git a/src/citra_qt/multiplayer/message.h b/src/citra_qt/multiplayer/message.h
index 8e719de8e..46461c3c1 100644
--- a/src/citra_qt/multiplayer/message.h
+++ b/src/citra_qt/multiplayer/message.h
@@ -20,9 +20,11 @@ private:
     std::string err;
 };
 
+/// When the nickname is considered invalid by the client
 extern const ConnectionError USERNAME_NOT_VALID;
 extern const ConnectionError ROOMNAME_NOT_VALID;
-extern const ConnectionError USERNAME_IN_USE;
+/// When the nickname is considered invalid by the room server
+extern const ConnectionError USERNAME_NOT_VALID_SERVER;
 extern const ConnectionError IP_ADDRESS_NOT_VALID;
 extern const ConnectionError PORT_NOT_VALID;
 extern const ConnectionError NO_INTERNET;
diff --git a/src/citra_qt/multiplayer/state.cpp b/src/citra_qt/multiplayer/state.cpp
index 461e1b5ca..d5c15dcb6 100644
--- a/src/citra_qt/multiplayer/state.cpp
+++ b/src/citra_qt/multiplayer/state.cpp
@@ -97,7 +97,7 @@ void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& s
         NetworkMessage::ShowError(NetworkMessage::UNABLE_TO_CONNECT);
         break;
     case Network::RoomMember::State::NameCollision:
-        NetworkMessage::ShowError(NetworkMessage::USERNAME_IN_USE);
+        NetworkMessage::ShowError(NetworkMessage::USERNAME_NOT_VALID_SERVER);
         break;
     case Network::RoomMember::State::MacCollision:
         NetworkMessage::ShowError(NetworkMessage::MAC_COLLISION);
diff --git a/src/network/room.cpp b/src/network/room.cpp
index db2a1a1fe..a5c39d2b6 100644
--- a/src/network/room.cpp
+++ b/src/network/room.cpp
@@ -7,6 +7,7 @@
 #include <iomanip>
 #include <mutex>
 #include <random>
+#include <regex>
 #include <sstream>
 #include <thread>
 #include "common/logging/log.h"
@@ -263,8 +264,12 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
 }
 
 bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const {
-    // A nickname is valid if it is not already taken by anybody else in the room.
-    // TODO(B3N30): Check for empty names, spaces, etc.
+    // A nickname is valid if it matches the regex and is not already taken by anybody else in the
+    // room.
+    const std::regex nickname_regex("^[ a-zA-Z0-9._-]{4,20}$");
+    if (!std::regex_match(nickname, nickname_regex))
+        return false;
+
     std::lock_guard<std::mutex> lock(member_mutex);
     return std::all_of(members.begin(), members.end(),
                        [&nickname](const auto& member) { return member.nickname != nickname; });