diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 841bbb13ea787324c95dd7b65277c535699ae0ee..bb2364c5c655df2dad61c602100b2a96baa48c6b 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -1959,6 +1959,10 @@ static void SendAskInfo(INT32 node)
 
 serverelem_t serverlist[MAXSERVERLIST];
 UINT32 serverlistcount = 0;
+UINT32 serverlistultimatecount = 0;
+
+static boolean resendserverlistnode[MAXNETNODES];
+static tic_t serverlistepoch;
 
 static void SL_ClearServerList(INT32 connectedserver)
 {
@@ -1971,6 +1975,8 @@ static void SL_ClearServerList(INT32 connectedserver)
 			serverlist[i].node = 0;
 		}
 	serverlistcount = 0;
+
+	memset(resendserverlistnode, 0, sizeof resendserverlistnode);
 }
 
 static UINT32 SL_SearchServer(INT32 node)
@@ -1987,6 +1993,8 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
 {
 	UINT32 i;
 
+	resendserverlistnode[node] = false;
+
 	// search if not already on it
 	i = SL_SearchServer(node);
 	if (i == UINT32_MAX)
@@ -2044,6 +2052,8 @@ void CL_QueryServerList (msg_server_t *server_list)
 
 	CL_UpdateServerList();
 
+	serverlistepoch = I_GetTime();
+
 	for (i = 0; server_list[i].header.buffer[0]; i++)
 	{
 		// Make sure MS version matches our own, to
@@ -2056,19 +2066,42 @@ void CL_QueryServerList (msg_server_t *server_list)
 			if (node == -1)
 				break; // no more node free
 			SendAskInfo(node);
-			// Force close the connection so that servers can't eat
-			// up nodes forever if we never get a reply back from them
-			// (usually when they've not forwarded their ports).
-			//
-			// Don't worry, we'll get in contact with the working
-			// servers again when they send SERVERINFO to us later!
-			//
-			// (Note: as a side effect this probably means every
-			// server in the list will probably be using the same node (e.g. node 1),
-			// not that it matters which nodes they use when
-			// the connections are closed afterwards anyway)
-			// -- Monster Iestyn 12/11/18
-			Net_CloseConnection(node|FORCECLOSE);
+			resendserverlistnode[node] = true;
+			// Leave this node open. It'll be closed if the
+			// request times out (CL_TimeoutServerList).
+		}
+	}
+
+	serverlistultimatecount = i;
+}
+
+#define SERVERLISTRESENDRATE NEWTICRATE
+
+void CL_TimeoutServerList(void)
+{
+	if (netgame && serverlistultimatecount > serverlistcount)
+	{
+		const tic_t timediff = I_GetTime() - serverlistepoch;
+		const tic_t timetoresend = timediff % SERVERLISTRESENDRATE;
+		const boolean timedout = timediff > connectiontimeout;
+
+		if (timedout || (timediff > 0 && timetoresend == 0))
+		{
+			INT32 node;
+
+			for (node = 1; node < MAXNETNODES; ++node)
+			{
+				if (resendserverlistnode[node])
+				{
+					if (timedout)
+						Net_CloseConnection(node|FORCECLOSE);
+					else
+						SendAskInfo(node);
+				}
+			}
+
+			if (timedout)
+				serverlistultimatecount = serverlistcount;
 		}
 	}
 }
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index ee05761566fb3216cdaef0fc0e8c2ac2876d09b6..4f8d098e31691ac6b0678e48c567752ceb8fc550 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -502,6 +502,7 @@ typedef struct
 
 extern serverelem_t serverlist[MAXSERVERLIST];
 extern UINT32 serverlistcount;
+extern UINT32 serverlistultimatecount;
 extern INT32 mapchangepending;
 
 // Points inside doomcom
@@ -594,6 +595,7 @@ void CL_ClearPlayer(INT32 playernum);
 void CL_RemovePlayer(INT32 playernum, INT32 reason);
 void CL_QueryServerList(msg_server_t *list);
 void CL_UpdateServerList(void);
+void CL_TimeoutServerList(void);
 // Is there a game running
 boolean Playing(void);
 
diff --git a/src/m_menu.c b/src/m_menu.c
index ab0f20208a92417d3e896cbbe5cc320ef0bdf7bf..f01703016a0068a03475a64176df9e8f0b73ea73 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -157,6 +157,8 @@ UINT8 maplistoption = 0;
 static char joystickInfo[8][29];
 #ifndef NONET
 static UINT32 serverlistpage;
+static UINT32 oldserverlistpage;
+static float serverlistslidex;
 #endif
 
 //static saveinfo_t savegameinfo[MAXSAVEGAMES]; // Extra info about the save games.
@@ -3479,6 +3481,8 @@ void M_Ticker(void)
 	}
 	I_unlock_mutex(ms_ServerList_mutex);
 #endif
+
+	CL_TimeoutServerList();
 }
 
 //
@@ -8569,12 +8573,18 @@ static void M_HandleServerPage(INT32 choice)
 		case KEY_RIGHTARROW:
 			S_StartSound(NULL, sfx_menu1);
 			if ((serverlistpage + 1) * SERVERS_PER_PAGE < serverlistcount)
-				serverlistpage++;
+			{
+				oldserverlistpage = serverlistpage++;
+				serverlistslidex = BASEVIDWIDTH;
+			}
 			break;
 		case KEY_LEFTARROW:
 			S_StartSound(NULL, sfx_menu1);
 			if (serverlistpage > 0)
-				serverlistpage--;
+			{
+				oldserverlistpage = serverlistpage--;
+				serverlistslidex = -(BASEVIDWIDTH);
+			}
 			break;
 
 		default:
@@ -8601,119 +8611,160 @@ static void M_Refresh(INT32 choice)
 {
 	(void)choice;
 
-	// Display a little "please wait" message.
-	M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
-	V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Searching for servers...");
-	V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
-	I_OsPolling();
-	I_UpdateNoBlit();
-	if (rendermode == render_soft)
-		I_FinishUpdate(); // page flip or blit buffer
-
 	// first page of servers
 	serverlistpage = 0;
 
+	CL_UpdateServerList();
+
 #ifdef MASTERSERVER
 #ifdef HAVE_THREADS
 	Spawn_masterserver_thread("fetch-servers", Fetch_servers_thread);
 #else/*HAVE_THREADS*/
 	Fetch_servers_thread(NULL);
 #endif/*HAVE_THREADS*/
-#else/*MASTERSERVER*/
-	CL_UpdateServerList();
 #endif/*MASTERSERVER*/
 }
 
-static void M_DrawConnectMenu(void)
+static void M_DrawServerCountAndHorizontalBar(void)
 {
-	UINT16 i;
-	const char *gt = "Unknown";
-	const char *spd = "";
-	INT32 numPages = (serverlistcount+(SERVERS_PER_PAGE-1))/SERVERS_PER_PAGE;
-	int waiting;
-	int mservflags = V_ALLOWLOWERCASE;
+	const char *text;
+	INT32 radius;
+	INT32 center = BASEVIDWIDTH/2;
 
-	for (i = FIRSTSERVERLINE; i < min(localservercount, SERVERS_PER_PAGE)+FIRSTSERVERLINE; i++)
-		MP_ConnectMenu[i].status = IT_STRING | IT_SPACE;
+	switch (M_GetWaitingMode())
+	{
+		case M_WAITING_VERSION:
+			text = "Checking for updates";
+			break;
 
-	if (!numPages)
-		numPages = 1;
+		case M_WAITING_SERVERS:
+			text = "Loading server list";
+			break;
 
-	// Page num
-	V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_page].alphaKey,
-	                         highlightflags, va("%u of %d", serverlistpage+1, numPages));
+		default:
+			if (serverlistultimatecount > serverlistcount)
+			{
+				text = va("%d/%d servers found%.*s",
+						serverlistcount,
+						serverlistultimatecount,
+						I_GetTime() / NEWTICRATE % 4, "...");
+			}
+			else if (serverlistcount > 0)
+			{
+				text = va("%d servers found", serverlistcount);
+			}
+			else
+			{
+				text = "No servers found";
+			}
+	}
 
-	// Did you change the Server Browser address? Have a little reminder.
-	if (CV_IsSetToDefault(&cv_masterserver))
-		mservflags = mservflags|highlightflags|V_30TRANS;
-	else
-		mservflags = mservflags|warningflags;
-	V_DrawRightAlignedSmallString(BASEVIDWIDTH - currentMenu->x, currentMenu->y+14 + MP_ConnectMenu[mp_connect_page].alphaKey,
-	                         mservflags, va("MS: %s", cv_masterserver.string));
+	radius = V_StringWidth(text, 0) / 2;
+
+	V_DrawCenteredString(center, currentMenu->y+28, 0, text);
 
 	// Horizontal line!
-	V_DrawFill(1, currentMenu->y+32, 318, 1, 0);
+	V_DrawFill(1, currentMenu->y+32, center - radius - 2, 1, 0);
+	V_DrawFill(center + radius + 2, currentMenu->y+32, BASEVIDWIDTH - 1, 1, 0);
+}
 
-	if (serverlistcount <= 0)
-		V_DrawString(currentMenu->x,currentMenu->y+SERVERHEADERHEIGHT, 0, "No servers found");
-	else
-	for (i = 0; i < min(serverlistcount - serverlistpage * SERVERS_PER_PAGE, SERVERS_PER_PAGE); i++)
+static void M_DrawServerLines(INT32 x, INT32 page)
+{
+	UINT16 i;
+	const char *gt = "Unknown";
+	const char *spd = "";
+
+	for (i = 0; i < min(serverlistcount - page * SERVERS_PER_PAGE, SERVERS_PER_PAGE); i++)
 	{
-		INT32 slindex = i + serverlistpage * SERVERS_PER_PAGE;
+		INT32 slindex = i + page * SERVERS_PER_PAGE;
 		UINT32 globalflags = ((serverlist[slindex].info.numberofplayer >= serverlist[slindex].info.maxplayer) ? V_TRANSLUCENT : 0)
 			|((itemOn == FIRSTSERVERLINE+i) ? highlightflags : 0)|V_ALLOWLOWERCASE;
 
-		V_DrawString(currentMenu->x, S_LINEY(i), globalflags, serverlist[slindex].info.servername);
+		V_DrawString(x, S_LINEY(i), globalflags, serverlist[slindex].info.servername);
 
 		// Don't use color flags intentionally, the global yellow color will auto override the text color code
 		if (serverlist[slindex].info.modifiedgame)
-			V_DrawSmallString(currentMenu->x+202, S_LINEY(i)+8, globalflags, "\x85" "Mod");
+			V_DrawSmallString(x+202, S_LINEY(i)+8, globalflags, "\x85" "Mod");
 		if (serverlist[slindex].info.cheatsenabled)
-			V_DrawSmallString(currentMenu->x+222, S_LINEY(i)+8, globalflags, "\x83" "Cheats");
+			V_DrawSmallString(x+222, S_LINEY(i)+8, globalflags, "\x83" "Cheats");
 
-		V_DrawSmallString(currentMenu->x, S_LINEY(i)+8, globalflags,
+		V_DrawSmallString(x, S_LINEY(i)+8, globalflags,
 		                     va("Ping: %u", (UINT32)LONG(serverlist[slindex].info.time)));
 
 		gt = "Unknown";
 		if (serverlist[slindex].info.gametype < NUMGAMETYPES)
 			gt = Gametype_Names[serverlist[slindex].info.gametype];
 
-		V_DrawSmallString(currentMenu->x+46,S_LINEY(i)+8, globalflags,
+		V_DrawSmallString(x+46,S_LINEY(i)+8, globalflags,
 		                         va("Players: %02d/%02d", serverlist[slindex].info.numberofplayer, serverlist[slindex].info.maxplayer));
 
-		V_DrawSmallString(currentMenu->x+112, S_LINEY(i)+8, globalflags, gt);
+		V_DrawSmallString(x+112, S_LINEY(i)+8, globalflags, gt);
 
 		// display game speed for race gametypes
 		if (serverlist[slindex].info.gametype == GT_RACE)
 		{
 			spd = kartspeed_cons_t[serverlist[slindex].info.kartvars & SV_SPEEDMASK].strvalue;
 
-			V_DrawSmallString(currentMenu->x+132, S_LINEY(i)+8, globalflags, va("(%s Speed)", spd));
+			V_DrawSmallString(x+132, S_LINEY(i)+8, globalflags, va("(%s Speed)", spd));
 		}
 
 		MP_ConnectMenu[i+FIRSTSERVERLINE].status = IT_STRING | IT_CALL;
 	}
+}
 
-	localservercount = serverlistcount;
+static void M_DrawConnectMenu(void)
+{
+	UINT16 i;
+	INT32 numPages = (serverlistcount+(SERVERS_PER_PAGE-1))/SERVERS_PER_PAGE;
+	INT32 mservflags = V_ALLOWLOWERCASE;
 
-	M_DrawGenericMenu();
+	for (i = FIRSTSERVERLINE; i < min(localservercount, SERVERS_PER_PAGE)+FIRSTSERVERLINE; i++)
+		MP_ConnectMenu[i].status = IT_STRING | IT_SPACE;
+
+	if (!numPages)
+		numPages = 1;
+
+	// Page num
+	V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_page].alphaKey,
+	                         highlightflags, va("%u of %d", serverlistpage+1, numPages));
 
-	waiting = M_GetWaitingMode();
+	// Did you change the Server Browser address? Have a little reminder.
+	if (CV_IsSetToDefault(&cv_masterserver))
+		mservflags = mservflags|highlightflags|V_30TRANS;
+	else
+		mservflags = mservflags|warningflags;
+	V_DrawRightAlignedSmallString(BASEVIDWIDTH - currentMenu->x, currentMenu->y+3 + MP_ConnectMenu[mp_connect_refresh].alphaKey,
+	                         mservflags, va("MS: %s", cv_masterserver.string));
+
+	M_DrawServerCountAndHorizontalBar();
 
-	if (waiting)
+	// When switching pages, slide the old page and the
+	// new page across the screen
+	if (oldserverlistpage != serverlistpage)
 	{
-		const char *message;
+		const float ease = serverlistslidex / 2.f;
+		const INT32 offx = serverlistslidex > 0 ? BASEVIDWIDTH : -(BASEVIDWIDTH);
+		const INT32 x = (FLOAT_TO_FIXED(serverlistslidex) + ease * rendertimefrac) / FRACUNIT;
 
-		if (waiting == M_WAITING_VERSION)
-			message = "Checking for updates...";
-		else
-			message = "Searching for servers...";
+		M_DrawServerLines(currentMenu->x + x - offx, oldserverlistpage);
+		M_DrawServerLines(currentMenu->x + x, serverlistpage);
+
+		if (interpTimerHackAllow)
+		{
+			serverlistslidex -= ease;
 
-		// Display a little "please wait" message.
-		M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
-		V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, message);
-		V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
+			if ((INT32)serverlistslidex == 0)
+				oldserverlistpage = serverlistpage;
+		}
+	}
+	else
+	{
+		M_DrawServerLines(currentMenu->x, serverlistpage);
 	}
+
+	localservercount = serverlistcount;
+
+	M_DrawGenericMenu();
 }
 
 static boolean M_CancelConnect(void)
@@ -8840,6 +8891,9 @@ static void M_ConnectMenu(INT32 choice)
 
 	// first page of servers
 	serverlistpage = 0;
+
+	CL_UpdateServerList();
+
 	M_SetupNextMenu(&MP_ConnectDef);
 	itemOn = 0;