How to stop connections piling up on your server

Connecting to Heartbeat or starting a loop on every respawn or remote call adds work that never stops. How to keep one connection per player or one shared loop.

warningLuaudit check: piling-connections

What it looks like

Each remote call, respawn or equip connects a new event handler or starts a new loop, and nothing stops the old one. Every repeat adds more work that runs for the rest of the server's life.

Luau
remote.OnServerEvent:Connect(function(player)
	RunService.Heartbeat:Connect(function()
		spin(player)
	end)
end)

How to detect it

  • Look for :Connect, task.spawn, task.delay, coroutine.wrap and while loops inside remote handlers, CharacterAdded, Equipped, Touched and other events that fire again and again.
  • For each one, find what stops it: a stored connection that's disconnected, a loop condition that ends, or the instance it's connected to being destroyed.
  • Destroying an instance disconnects connections to its own events. Connections to RunService, Players, a Player, workspace or any other long-lived object stay until they're disconnected.
  • Loops that check a flag should check one that belongs to this run. A shared "enabled" flag switched off and on again leaves the first loop running beside the second.

What an exploiter could do

They repeat whatever starts the work, by firing the remote, respawning or re-equipping a tool, and each repeat adds another handler or loop. The server spends more and more time on them every frame and holds on to more memory, until it's slow for everyone in it. Unlike a burst of calls, the cost stays after they stop.

How to fix it

  • Keep each player's connection or loop in a table. Disconnect or stop the old one before starting a new one, and clean up in Players.PlayerRemoving.
  • Prefer one shared loop that goes over a table of active players, over a loop per player or per call.
  • Connect to the character's own parts and humanoid where you can, and make sure old characters are destroyed: turn on Workspace.PlayerCharacterDestroyBehavior, or destroy old characters yourself once they have been replaced.

Vulnerable example

Vulnerable
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

ReplicatedStorage.Remotes.ToggleAura.OnServerEvent:Connect(function(player: Player, enabled: unknown)
	if typeof(enabled) ~= "boolean" then
		return
	end
	player:SetAttribute("Aura", enabled)
	if not enabled then
		return
	end
	RunService.Heartbeat:Connect(function()
		local character = player.Character
		local aura = character and character:FindFirstChild("Aura")
		if aura and aura:IsA("BasePart") and player:GetAttribute("Aura") then
			aura.CFrame *= CFrame.Angles(0, math.rad(2), 0)
		end
	end)
end)

Fixed example

Fixed
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

local active: { [Player]: boolean } = {}

ReplicatedStorage.Remotes.ToggleAura.OnServerEvent:Connect(function(player: Player, enabled: unknown)
	if typeof(enabled) ~= "boolean" then
		return
	end
	if enabled then
		active[player] = true
	else
		active[player] = nil
	end
end)

Players.PlayerRemoving:Connect(function(player)
	active[player] = nil
end)

RunService.Heartbeat:Connect(function()
	for player in active do
		local character = player.Character
		local aura = character and character:FindFirstChild("Aura")
		if aura and aura:IsA("BasePart") then
			aura.CFrame *= CFrame.Angles(0, math.rad(2), 0)
		end
	end
end)

Common false positives

  • Connections made once at startup, or once per player in PlayerAdded, don't pile up.
  • Connections to parts inside the character, or to its Humanoid, end when the character is destroyed. Roblox destroys old characters on respawn when Workspace.PlayerCharacterDestroyBehavior is enabled. Otherwise check the game destroys them itself.
  • A loop that checks something unique to its own run, like whether its character is still the player's current one, ends by itself.