diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c
index 7804b068f7f8d262bd7fab535539af82675bd639..3e401105fd6d1dccd2e9e8a6bafe0440f3b5e576 100644
--- a/src/netcode/d_clisrv.c
+++ b/src/netcode/d_clisrv.c
@@ -1275,6 +1275,7 @@ static void UpdatePingTable(void)
 	}
 }
 
+// Handle idle and disconnected player timers
 static void IdleUpdate(void)
 {
 	INT32 i;
@@ -1297,7 +1298,35 @@ static void IdleUpdate(void)
 			}
 		}
 		else
+		{
 			players[i].lastinputtime = 0;
+
+			if (players[i].quittime && playeringame[i])
+			{
+				players[i].quittime++;
+
+				if (players[i].quittime == 30 * TICRATE && G_TagGametype())
+					P_CheckSurvivors();
+
+				if (server && players[i].quittime >= (tic_t)FixedMul(cv_rejointimeout.value, 60 * TICRATE)
+				&& !(players[i].quittime % TICRATE))
+				{
+					boolean send = false; // Only broadcast the kick if any nodes are connected
+					for (INT32 j = 1; j < MAXNETNODES; j++)
+					{
+						if (netnodes[j].ingame)
+						{
+							send = true;
+							break;
+						}
+					}
+					if (send)
+						SendKick(i, KICK_MSG_PLAYER_QUIT);
+					else // If the server is empty, don't send a NetXCmd - that would wake an idling dedicated server
+						CL_RemovePlayer(i, KICK_MSG_PLAYER_QUIT);
+				}
+			}
+		}
 	}
 }
 
diff --git a/src/p_tick.c b/src/p_tick.c
index 1bc7b78bf1a39499576794b8e80d7181f58cd43c..3934890f19a585a8c1c657ea753801c21688dd35 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -690,25 +690,11 @@ void P_Ticker(boolean run)
 {
 	INT32 i;
 
-	// Increment jointime and quittime even if paused
+	// Increment jointime even if paused
 	for (i = 0; i < MAXPLAYERS; i++)
 		if (playeringame[i])
-		{
 			players[i].jointime++;
 
-			if (players[i].quittime)
-			{
-				players[i].quittime++;
-
-				if (players[i].quittime == 30 * TICRATE && G_TagGametype())
-					P_CheckSurvivors();
-
-				if (server && players[i].quittime >= (tic_t)FixedMul(cv_rejointimeout.value, 60 * TICRATE)
-				&& !(players[i].quittime % TICRATE))
-					SendKick(i, KICK_MSG_PLAYER_QUIT);
-			}
-		}
-
 	if (objectplacing)
 	{
 		if (OP_FreezeObjectplace())