diff --git a/include/mtxclient/http/client.hpp b/include/mtxclient/http/client.hpp
index 88df02aac0434ed50a9e18f40d2bd2776dcd7eb1..b90e7f574b65c476f0142684e7aedd453479f19a 100644
--- a/include/mtxclient/http/client.hpp
+++ b/include/mtxclient/http/client.hpp
@@ -73,7 +73,7 @@ public:
         //! Wait for the client to close.
         void close();
         //! Set the homeserver domain name.
-        void set_server(const std::string &server) { server_ = server; };
+        void set_server(const std::string &server);
         //! Retrieve the homeserver domain name.
         std::string server() { return server_; };
         //! Set the homeserver port.
diff --git a/include/mtxclient/utils.hpp b/include/mtxclient/utils.hpp
index 0752ddb8784e47580be3541bdb31b58035331225..92816027e15d4a271a8cd67802ccf20e10968e39 100644
--- a/include/mtxclient/utils.hpp
+++ b/include/mtxclient/utils.hpp
@@ -10,6 +10,10 @@ namespace mtx {
 namespace client {
 namespace utils {
 
+//! Check if the given string represents a number.
+bool
+is_number(const std::string &s);
+
 //! Generates a random string of the given size.
 std::string
 random_token(uint8_t len = 12, bool with_symbols = true) noexcept;
diff --git a/lib/http/client.cpp b/lib/http/client.cpp
index 1a1039a54b68db488a2cb0f249cb730815b4f102..8397756c5676f582b4cf9d9b10bc38048060c624 100644
--- a/lib/http/client.cpp
+++ b/lib/http/client.cpp
@@ -22,6 +22,21 @@ Client::Client(const std::string &server, uint16_t port)
                 thread_group_.add_thread(new boost::thread([this]() { ios_.run(); }));
 }
 
+void
+Client::set_server(const std::string &server)
+{
+        // Check if the input also contains the port.
+        std::vector<std::string> parts;
+        boost::split(parts, server, [](char c) { return c == ':'; });
+
+        if (parts.size() == 2 && mtx::client::utils::is_number(parts.at(1))) {
+                server_ = parts.at(0);
+                port_   = std::stoi(parts.at(1));
+        } else {
+                server_ = server;
+        }
+};
+
 void
 Client::close()
 {
diff --git a/lib/utils.cpp b/lib/utils.cpp
index 7a36b37a80c0015466a39e9f679a366646b13c40..3f6a73fc7bd7b7b906db9e077d114daf7a574738 100644
--- a/lib/utils.cpp
+++ b/lib/utils.cpp
@@ -14,6 +14,13 @@
 #include <boost/random/random_device.hpp>
 #include <boost/random/uniform_int_distribution.hpp>
 
+bool
+mtx::client::utils::is_number(const std::string &s)
+{
+        return !s.empty() &&
+               std::find_if(s.begin(), s.end(), [](char c) { return !std::isdigit(c); }) == s.end();
+}
+
 std::string
 mtx::client::utils::random_token(uint8_t len, bool with_symbols) noexcept
 {
diff --git a/tests/connection.cpp b/tests/connection.cpp
index 3d5168546f1bc4cf9e7c91891b0a624320d48b46..0445dfd3cc3cf249858667d372bdd4142e11563e 100644
--- a/tests/connection.cpp
+++ b/tests/connection.cpp
@@ -25,6 +25,19 @@ TEST(Basic, Connection)
         alice->close();
 }
 
+TEST(Basic, ServerWithPort)
+{
+        auto alice = std::make_shared<Client>("matrix.org");
+        alice->set_server("localhost:8448");
+
+        EXPECT_EQ(alice->server(), "localhost");
+        EXPECT_EQ(alice->port(), 8448);
+
+        alice->versions(
+          [](const mtx::responses::Versions &, RequestErr err) { ASSERT_FALSE(err); });
+        alice->close();
+}
+
 TEST(Basic, Failure)
 {
         auto alice = std::make_shared<Client>("not-resolvable-example-domain.wrong");