diff --git a/Agent/Phantom.Agent.Services/AgentServices.cs b/Agent/Phantom.Agent.Services/AgentServices.cs
index c31e118..304631b 100644
--- a/Agent/Phantom.Agent.Services/AgentServices.cs
+++ b/Agent/Phantom.Agent.Services/AgentServices.cs
@@ -6,7 +6,6 @@ using Phantom.Agent.Services.Instances;
 using Phantom.Common.Data.Agent;
 using Phantom.Utils.Actor;
 using Phantom.Utils.Logging;
-using Phantom.Utils.Tasks;
 using Serilog;
 
 namespace Phantom.Agent.Services;
@@ -18,7 +17,6 @@ public sealed class AgentServices {
 
 	private AgentFolders AgentFolders { get; }
 	private AgentState AgentState { get; }
-	private TaskManager TaskManager { get; }
 	private BackupManager BackupManager { get; }
 
 	internal JavaRuntimeRepository JavaRuntimeRepository { get; }
@@ -30,13 +28,12 @@ public sealed class AgentServices {
 		
 		this.AgentFolders = agentFolders;
 		this.AgentState = new AgentState();
-		this.TaskManager = new TaskManager(PhantomLogger.Create<TaskManager, AgentServices>());
 		this.BackupManager = new BackupManager(agentFolders, serviceConfiguration.MaxConcurrentCompressionTasks);
 		
 		this.JavaRuntimeRepository = new JavaRuntimeRepository();
 		this.InstanceTicketManager = new InstanceTicketManager(agentInfo, controllerConnection);
 		
-		var instanceManagerInit = new InstanceManagerActor.Init(controllerConnection, agentFolders, AgentState, JavaRuntimeRepository, InstanceTicketManager, TaskManager, BackupManager);
+		var instanceManagerInit = new InstanceManagerActor.Init(controllerConnection, agentFolders, AgentState, JavaRuntimeRepository, InstanceTicketManager, BackupManager);
 		this.InstanceManager = ActorSystem.ActorOf(InstanceManagerActor.Factory(instanceManagerInit), "InstanceManager");
 	}
 
@@ -50,7 +47,6 @@ public sealed class AgentServices {
 		Logger.Information("Stopping services...");
 		
 		await InstanceManager.Stop(new InstanceManagerActor.ShutdownCommand());
-		await TaskManager.Stop();
 		
 		BackupManager.Dispose();
 		
diff --git a/Agent/Phantom.Agent.Services/Backups/BackupScheduler.cs b/Agent/Phantom.Agent.Services/Backups/BackupScheduler.cs
index 3853625..4ff9a68 100644
--- a/Agent/Phantom.Agent.Services/Backups/BackupScheduler.cs
+++ b/Agent/Phantom.Agent.Services/Backups/BackupScheduler.cs
@@ -24,7 +24,7 @@ sealed class BackupScheduler : CancellableBackgroundTask {
 	
 	public event EventHandler<BackupCreationResult>? BackupCompleted;
 
-	public BackupScheduler(InstanceContext context, InstanceProcess process, int serverPort) : base(PhantomLogger.Create<BackupScheduler>(context.ShortName), context.Services.TaskManager, "Backup scheduler for " + context.ShortName) {
+	public BackupScheduler(InstanceContext context, InstanceProcess process, int serverPort) : base(PhantomLogger.Create<BackupScheduler>(context.ShortName)) {
 		this.backupManager = context.Services.BackupManager;
 		this.context = context;
 		this.process = process;
diff --git a/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs b/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs
index f036b51..2f95e79 100644
--- a/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs
+++ b/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs
@@ -20,7 +20,7 @@ namespace Phantom.Agent.Services.Instances;
 sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand> {
 	private static readonly ILogger Logger = PhantomLogger.Create<InstanceManagerActor>();
 
-	public readonly record struct Init(ControllerConnection ControllerConnection, AgentFolders AgentFolders, AgentState AgentState, JavaRuntimeRepository JavaRuntimeRepository, InstanceTicketManager InstanceTicketManager, TaskManager TaskManager, BackupManager BackupManager);
+	public readonly record struct Init(ControllerConnection ControllerConnection, AgentFolders AgentFolders, AgentState AgentState, JavaRuntimeRepository JavaRuntimeRepository, InstanceTicketManager InstanceTicketManager, BackupManager BackupManager);
 
 	public static Props<ICommand> Factory(Init init) {
 		return Props<ICommand>.Create(() => new InstanceManagerActor(init), new ActorConfiguration { SupervisorStrategy = SupervisorStrategies.Resume });
@@ -47,7 +47,7 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
 		var minecraftServerExecutables = new MinecraftServerExecutables(init.AgentFolders.ServerExecutableFolderPath);
 		var launchServices = new LaunchServices(minecraftServerExecutables, init.JavaRuntimeRepository);
 
-		this.instanceServices = new InstanceServices(init.ControllerConnection, init.TaskManager, init.BackupManager, launchServices);
+		this.instanceServices = new InstanceServices(init.ControllerConnection, init.BackupManager, launchServices);
 		
 		ReceiveAndReply<ConfigureInstanceCommand, InstanceActionResult<ConfigureInstanceResult>>(ConfigureInstance);
 		ReceiveAndReply<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
diff --git a/Agent/Phantom.Agent.Services/Instances/InstanceServices.cs b/Agent/Phantom.Agent.Services/Instances/InstanceServices.cs
index b8363ba..209e0c4 100644
--- a/Agent/Phantom.Agent.Services/Instances/InstanceServices.cs
+++ b/Agent/Phantom.Agent.Services/Instances/InstanceServices.cs
@@ -1,8 +1,7 @@
 using Phantom.Agent.Minecraft.Launcher;
 using Phantom.Agent.Rpc;
 using Phantom.Agent.Services.Backups;
-using Phantom.Utils.Tasks;
 
 namespace Phantom.Agent.Services.Instances;
 
-sealed record InstanceServices(ControllerConnection ControllerConnection, TaskManager TaskManager, BackupManager BackupManager, LaunchServices LaunchServices);
+sealed record InstanceServices(ControllerConnection ControllerConnection, BackupManager BackupManager, LaunchServices LaunchServices);
diff --git a/Agent/Phantom.Agent.Services/Instances/State/InstanceLogSender.cs b/Agent/Phantom.Agent.Services/Instances/State/InstanceLogSender.cs
index 8aa63a6..0915d8f 100644
--- a/Agent/Phantom.Agent.Services/Instances/State/InstanceLogSender.cs
+++ b/Agent/Phantom.Agent.Services/Instances/State/InstanceLogSender.cs
@@ -22,7 +22,7 @@ sealed class InstanceLogSender : CancellableBackgroundTask {
 	
 	private int droppedLinesSinceLastSend;
 
-	public InstanceLogSender(ControllerConnection controllerConnection, TaskManager taskManager, Guid instanceGuid, string loggerName) : base(PhantomLogger.Create<InstanceLogSender>(loggerName), taskManager, "Instance log sender for " + loggerName) {
+	public InstanceLogSender(ControllerConnection controllerConnection, Guid instanceGuid, string loggerName) : base(PhantomLogger.Create<InstanceLogSender>(loggerName)) {
 		this.controllerConnection = controllerConnection;
 		this.instanceGuid = instanceGuid;
 		this.outputChannel = Channel.CreateBounded<string>(BufferOptions, OnLineDropped);
diff --git a/Agent/Phantom.Agent.Services/Instances/State/InstanceRunningState.cs b/Agent/Phantom.Agent.Services/Instances/State/InstanceRunningState.cs
index 3d30b3b..1470682 100644
--- a/Agent/Phantom.Agent.Services/Instances/State/InstanceRunningState.cs
+++ b/Agent/Phantom.Agent.Services/Instances/State/InstanceRunningState.cs
@@ -31,7 +31,7 @@ sealed class InstanceRunningState : IDisposable {
 		this.Process = process;
 		this.cancellationToken = cancellationToken;
 
-		this.logSender = new InstanceLogSender(context.Services.ControllerConnection, context.Services.TaskManager, context.InstanceGuid, context.ShortName);
+		this.logSender = new InstanceLogSender(context.Services.ControllerConnection, context.InstanceGuid, context.ShortName);
 
 		this.backupScheduler = new BackupScheduler(context, process, configuration.ServerPort);
 		this.backupScheduler.BackupCompleted += OnScheduledBackupCompleted;
diff --git a/Controller/Phantom.Controller/Program.cs b/Controller/Phantom.Controller/Program.cs
index 63be6eb..29aa80c 100644
--- a/Controller/Phantom.Controller/Program.cs
+++ b/Controller/Phantom.Controller/Program.cs
@@ -10,7 +10,6 @@ using Phantom.Utils.Logging;
 using Phantom.Utils.Rpc;
 using Phantom.Utils.Rpc.Runtime;
 using Phantom.Utils.Runtime;
-using Phantom.Utils.Tasks;
 
 var shutdownCancellationTokenSource = new CancellationTokenSource();
 var shutdownCancellationToken = shutdownCancellationTokenSource.Token;
@@ -64,14 +63,12 @@ try {
 		return new RpcConfiguration(serviceName, host, port, connectionKey.Certificate);
 	}
 
-	var rpcTaskManager = new TaskManager(PhantomLogger.Create<TaskManager>("Rpc"));
 	try {
 		await Task.WhenAll(
 			RpcServerRuntime.Launch(ConfigureRpc("Agent", agentRpcServerHost, agentRpcServerPort, agentKeyData), AgentMessageRegistries.Definitions, controllerServices.AgentRegistrationHandler, controllerServices.ActorSystem, shutdownCancellationToken),
 			RpcServerRuntime.Launch(ConfigureRpc("Web", webRpcServerHost, webRpcServerPort, webKeyData), WebMessageRegistries.Definitions, controllerServices.WebRegistrationHandler, controllerServices.ActorSystem, shutdownCancellationToken)
 		);
 	} finally {
-		await rpcTaskManager.Stop();
 		NetMQConfig.Cleanup();
 	}
 
diff --git a/Utils/Phantom.Utils/Tasks/CancellableBackgroundTask.cs b/Utils/Phantom.Utils/Tasks/CancellableBackgroundTask.cs
index ee60040..cc4af28 100644
--- a/Utils/Phantom.Utils/Tasks/CancellableBackgroundTask.cs
+++ b/Utils/Phantom.Utils/Tasks/CancellableBackgroundTask.cs
@@ -8,19 +8,13 @@ public abstract class CancellableBackgroundTask {
 	protected ILogger Logger { get; }
 	protected CancellationToken CancellationToken { get; }
 
-	private readonly TaskManager taskManager;
-	private readonly string taskName;
-	
-	protected CancellableBackgroundTask(ILogger logger, TaskManager taskManager, string taskName) {
+	protected CancellableBackgroundTask(ILogger logger) {
 		this.Logger = logger;
 		this.CancellationToken = cancellationTokenSource.Token;
-		
-		this.taskManager = taskManager;
-		this.taskName = taskName;
 	}
 
 	protected void Start() {
-		taskManager.Run(taskName, Run);
+		Task.Run(Run, CancellationToken.None);
 	}
 
 	private async Task Run() {
diff --git a/Utils/Phantom.Utils/Tasks/TaskManager.cs b/Utils/Phantom.Utils/Tasks/TaskManager.cs
deleted file mode 100644
index e0064eb..0000000
--- a/Utils/Phantom.Utils/Tasks/TaskManager.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System.Collections.Concurrent;
-using Phantom.Utils.Collections;
-using Serilog;
-
-namespace Phantom.Utils.Tasks;
-
-public sealed class TaskManager {
-	private readonly ILogger logger;
-	private readonly CancellationTokenSource cancellationTokenSource = new ();
-	private readonly CancellationToken cancellationToken;
-	
-	private readonly ConcurrentDictionary<Task, string> runningTasks = new (ReferenceEqualityComparer<Task>.Instance);
-	
-	public TaskManager(ILogger logger) {
-		this.logger = logger;
-		this.cancellationToken = cancellationTokenSource.Token;
-	}
-
-	private T Add<T>(string name, T task) where T : Task {
-		cancellationToken.ThrowIfCancellationRequested();
-		runningTasks.TryAdd(task, name);
-		task.ContinueWith(OnFinished, CancellationToken.None, TaskContinuationOptions.RunContinuationsAsynchronously, TaskScheduler.Default);
-		return task;
-	}
-
-	private void OnFinished(Task task) {
-		runningTasks.TryRemove(task, out _);
-	}
-
-	public Task Run(string name, Action action) {
-		return Add(name, Task.Run(action, cancellationToken));
-	}
-
-	public Task Run(string name, Func<Task> taskFunc) {
-		return Add(name, Task.Run(taskFunc, cancellationToken));
-	}
-
-	public Task<T> Run<T>(string name, Func<Task<T>> taskFunc) {
-		return Add(name, Task.Run(taskFunc, cancellationToken));
-	}
-
-	public async Task Stop() {
-		logger.Information("Stopping task manager...");
-		
-		cancellationTokenSource.Cancel();
-
-		var remainingTasksAwaiterTask = WaitForRemainingTasks();
-		while (true) {
-			var logStateTimeoutTask = Task.Delay(TimeSpan.FromSeconds(10), CancellationToken.None);
-			var completedTask = await Task.WhenAny(remainingTasksAwaiterTask, logStateTimeoutTask);
-			if (completedTask == logStateTimeoutTask) {
-				var remainingTaskNames = runningTasks.Values.Order().ToList();
-				var remainingTaskNameList = string.Join('\n', remainingTaskNames.Select(static name => "- " + name));
-				logger.Warning("Waiting for {TaskCount} task(s) to finish:\n{TaskNames}", remainingTaskNames.Count, remainingTaskNameList);
-			}
-			else {
-				break;
-			}
-		}
-
-		runningTasks.Clear();
-		cancellationTokenSource.Dispose();
-		
-		logger.Information("Task manager stopped.");
-	}
-
-	private async Task WaitForRemainingTasks() {
-		foreach (var task in runningTasks.Keys) {
-			try {
-				await task;
-			} catch (Exception) {
-				// ignored
-			}
-		}
-	}
-}
diff --git a/Web/Phantom.Web/Program.cs b/Web/Phantom.Web/Program.cs
index 34c9b2a..831fa36 100644
--- a/Web/Phantom.Web/Program.cs
+++ b/Web/Phantom.Web/Program.cs
@@ -9,7 +9,6 @@ using Phantom.Utils.Logging;
 using Phantom.Utils.Rpc;
 using Phantom.Utils.Rpc.Sockets;
 using Phantom.Utils.Runtime;
-using Phantom.Utils.Tasks;
 using Phantom.Web;
 using Phantom.Web.Services;
 using Phantom.Web.Services.Rpc;
@@ -59,8 +58,7 @@ try {
 	var rpcSocket = RpcClientSocket.Connect(rpcConfiguration, WebMessageRegistries.Definitions, new RegisterWebMessage(webToken));
 
 	var webConfiguration = new WebLauncher.Configuration(PhantomLogger.Create("Web"), webServerHost, webServerPort, webBasePath, dataProtectionKeysPath, shutdownCancellationToken);
-	var taskManager = new TaskManager(PhantomLogger.Create<TaskManager>("Web"));
-	var webApplication = WebLauncher.CreateApplication(webConfiguration, taskManager, applicationProperties, rpcSocket.Connection);
+	var webApplication = WebLauncher.CreateApplication(webConfiguration, applicationProperties, rpcSocket.Connection);
 
 	using var actorSystem = ActorSystemFactory.Create("Web");
 	
@@ -88,7 +86,6 @@ try {
 		await WebLauncher.Launch(webConfiguration, webApplication);
 	} finally {
 		shutdownCancellationTokenSource.Cancel();
-		await taskManager.Stop();
 		
 		rpcDisconnectSemaphore.Release();
 		await rpcTask;
diff --git a/Web/Phantom.Web/WebLauncher.cs b/Web/Phantom.Web/WebLauncher.cs
index 7266a5f..cdabb4d 100644
--- a/Web/Phantom.Web/WebLauncher.cs
+++ b/Web/Phantom.Web/WebLauncher.cs
@@ -1,7 +1,6 @@
 using Microsoft.AspNetCore.DataProtection;
 using Phantom.Common.Messages.Web;
 using Phantom.Utils.Rpc.Runtime;
-using Phantom.Utils.Tasks;
 using Phantom.Web.Services;
 using Serilog;
 using ILogger = Serilog.ILogger;
@@ -13,7 +12,7 @@ static class WebLauncher {
 		public string HttpUrl => "http://" + Host + ":" + Port;
 	}
 	
-	internal static WebApplication CreateApplication(Configuration config, TaskManager taskManager, ApplicationProperties applicationProperties, RpcConnectionToServer<IMessageToController> controllerConnection) {
+	internal static WebApplication CreateApplication(Configuration config, ApplicationProperties applicationProperties, RpcConnectionToServer<IMessageToController> controllerConnection) {
 		var assembly = typeof(WebLauncher).Assembly;
 		var builder = WebApplication.CreateBuilder(new WebApplicationOptions {
 			ApplicationName = assembly.GetName().Name,
@@ -29,7 +28,6 @@ static class WebLauncher {
 			builder.WebHost.UseStaticWebAssets();
 		}
 
-		builder.Services.AddSingleton(taskManager);
 		builder.Services.AddSingleton(applicationProperties);
 		builder.Services.AddSingleton(controllerConnection);
 		builder.Services.AddPhantomServices();