diff --git a/src/Listen.cxx b/src/Listen.cxx
index ab08050db..3faccc954 100644
--- a/src/Listen.cxx
+++ b/src/Listen.cxx
@@ -50,9 +50,10 @@ public:
 		:ServerSocket(_loop), partition(_partition) {}
 
 private:
-	void OnAccept(int fd, SocketAddress address, int uid) override {
+	void OnAccept(UniqueSocketDescriptor &&fd,
+		      SocketAddress address, int uid) override {
 		client_new(GetEventLoop(), partition,
-			   SocketDescriptor(fd), address, uid);
+			   std::move(fd), address, uid);
 	}
 };
 
diff --git a/src/client/Client.hxx b/src/client/Client.hxx
index 1b7bcab50..6c895006c 100644
--- a/src/client/Client.hxx
+++ b/src/client/Client.hxx
@@ -38,6 +38,7 @@
 #include <stddef.h>
 
 class SocketAddress;
+class UniqueSocketDescriptor;
 class EventLoop;
 class Path;
 struct Instance;
@@ -94,7 +95,7 @@ public:
 	std::list<ClientMessage> messages;
 
 	Client(EventLoop &loop, Partition &partition,
-	       SocketDescriptor fd, int uid, int num);
+	       UniqueSocketDescriptor &&fd, int uid, int num);
 
 	~Client() {
 		if (FullyBufferedSocket::IsDefined())
@@ -236,7 +237,7 @@ client_manager_init();
 
 void
 client_new(EventLoop &loop, Partition &partition,
-	   SocketDescriptor fd, SocketAddress address, int uid);
+	   UniqueSocketDescriptor &&fd, SocketAddress address, int uid);
 
 /**
  * Write a printf-like formatted string to the client.
diff --git a/src/client/ClientNew.cxx b/src/client/ClientNew.cxx
index 6099acf4a..0b95b79b7 100644
--- a/src/client/ClientNew.cxx
+++ b/src/client/ClientNew.cxx
@@ -23,6 +23,7 @@
 #include "Partition.hxx"
 #include "Instance.hxx"
 #include "system/fd_util.h"
+#include "net/UniqueSocketDescriptor.hxx"
 #include "net/SocketAddress.hxx"
 #include "net/ToString.hxx"
 #include "Permission.hxx"
@@ -42,8 +43,9 @@
 static const char GREETING[] = "OK MPD " PROTOCOL_VERSION "\n";
 
 Client::Client(EventLoop &_loop, Partition &_partition,
-	       SocketDescriptor _fd, int _uid, int _num)
-	:FullyBufferedSocket(_fd, _loop, 16384, client_max_output_buffer_size),
+	       UniqueSocketDescriptor &&_fd, int _uid, int _num)
+	:FullyBufferedSocket(_fd.Release(), _loop,
+			     16384, client_max_output_buffer_size),
 	 TimeoutMonitor(_loop),
 	 partition(&_partition),
 	 permission(getDefaultPermissions()),
@@ -57,7 +59,7 @@ Client::Client(EventLoop &_loop, Partition &_partition,
 
 void
 client_new(EventLoop &loop, Partition &partition,
-	   SocketDescriptor fd, SocketAddress address, int uid)
+	   UniqueSocketDescriptor &&fd, SocketAddress address, int uid)
 {
 	static unsigned int next_client_num;
 	const auto remote = ToString(address);
@@ -80,7 +82,6 @@ client_new(EventLoop &loop, Partition &partition,
 				      "libwrap refused connection (libwrap=%s) from %s",
 				      progname, remote.c_str());
 
-			fd.Close();
 			return;
 		}
 	}
@@ -89,15 +90,14 @@ client_new(EventLoop &loop, Partition &partition,
 	ClientList &client_list = *partition.instance.client_list;
 	if (client_list.IsFull()) {
 		LogWarning(client_domain, "Max connections reached");
-		fd.Close();
 		return;
 	}
 
-	Client *client = new Client(loop, partition, fd, uid,
-				    next_client_num++);
-
 	(void)fd.Write(GREETING, sizeof(GREETING) - 1);
 
+	Client *client = new Client(loop, partition, std::move(fd), uid,
+				    next_client_num++);
+
 	client_list.Add(*client);
 
 	FormatInfo(client_domain, "[%u] opened from %s",
diff --git a/src/event/ServerSocket.cxx b/src/event/ServerSocket.cxx
index 3d3716f10..85cf93dbe 100644
--- a/src/event/ServerSocket.cxx
+++ b/src/event/ServerSocket.cxx
@@ -150,7 +150,7 @@ inline void
 OneServerSocket::Accept() noexcept
 {
 	StaticSocketAddress peer_address;
-	auto peer_fd = Get().AcceptNonBlock(peer_address);
+	UniqueSocketDescriptor peer_fd(Get().AcceptNonBlock(peer_address));
 	if (!peer_fd.IsDefined()) {
 		const SocketErrorMessage msg;
 		FormatError(server_socket_domain,
@@ -165,7 +165,7 @@ OneServerSocket::Accept() noexcept
 			    (const char *)msg);
 	}
 
-	parent.OnAccept(peer_fd.Get(), peer_address,
+	parent.OnAccept(std::move(peer_fd), peer_address,
 			get_remote_uid(peer_fd.Get()));
 }
 
diff --git a/src/event/ServerSocket.hxx b/src/event/ServerSocket.hxx
index 875bdd3bb..9e44143e3 100644
--- a/src/event/ServerSocket.hxx
+++ b/src/event/ServerSocket.hxx
@@ -24,6 +24,7 @@
 
 class SocketAddress;
 class AllocatedSocketAddress;
+class UniqueSocketDescriptor;
 class EventLoop;
 class AllocatedPath;
 class OneServerSocket;
@@ -116,7 +117,8 @@ public:
 	void Close();
 
 protected:
-	virtual void OnAccept(int fd, SocketAddress address, int uid) = 0;
+	virtual void OnAccept(UniqueSocketDescriptor &&fd,
+			      SocketAddress address, int uid) = 0;
 };
 
 #endif
diff --git a/src/output/plugins/httpd/HttpdClient.cxx b/src/output/plugins/httpd/HttpdClient.cxx
index d37ce5ff4..c62cd17e1 100644
--- a/src/output/plugins/httpd/HttpdClient.cxx
+++ b/src/output/plugins/httpd/HttpdClient.cxx
@@ -25,6 +25,7 @@
 #include "Page.hxx"
 #include "IcyMetaDataServer.hxx"
 #include "net/SocketError.hxx"
+#include "net/UniqueSocketDescriptor.hxx"
 #include "Log.hxx"
 
 #include <assert.h>
@@ -185,10 +186,10 @@ HttpdClient::SendResponse()
 	return true;
 }
 
-HttpdClient::HttpdClient(HttpdOutput &_httpd, SocketDescriptor _fd,
+HttpdClient::HttpdClient(HttpdOutput &_httpd, UniqueSocketDescriptor &&_fd,
 			 EventLoop &_loop,
 			 bool _metadata_supported)
-	:BufferedSocket(_fd, _loop),
+	:BufferedSocket(_fd.Release(), _loop),
 	 httpd(_httpd),
 	 state(REQUEST),
 	 queue_size(0),
diff --git a/src/output/plugins/httpd/HttpdClient.hxx b/src/output/plugins/httpd/HttpdClient.hxx
index b4da2cd4c..128e17eeb 100644
--- a/src/output/plugins/httpd/HttpdClient.hxx
+++ b/src/output/plugins/httpd/HttpdClient.hxx
@@ -32,6 +32,7 @@
 
 #include <stddef.h>
 
+class UniqueSocketDescriptor;
 class HttpdOutput;
 
 class HttpdClient final
@@ -131,7 +132,8 @@ public:
 	 * @param httpd the HTTP output device
 	 * @param _fd the socket file descriptor
 	 */
-	HttpdClient(HttpdOutput &httpd, SocketDescriptor _fd, EventLoop &_loop,
+	HttpdClient(HttpdOutput &httpd, UniqueSocketDescriptor &&_fd,
+		    EventLoop &_loop,
 		    bool _metadata_supported);
 
 	/**
diff --git a/src/output/plugins/httpd/HttpdInternal.hxx b/src/output/plugins/httpd/HttpdInternal.hxx
index 3dd7d1d0c..f7df99c57 100644
--- a/src/output/plugins/httpd/HttpdInternal.hxx
+++ b/src/output/plugins/httpd/HttpdInternal.hxx
@@ -206,7 +206,7 @@ public:
 		return HasClients();
 	}
 
-	void AddClient(SocketDescriptor fd);
+	void AddClient(UniqueSocketDescriptor &&fd);
 
 	/**
 	 * Removes a client from the httpd_output.clients linked list.
@@ -257,7 +257,8 @@ public:
 private:
 	virtual void RunDeferred() override;
 
-	void OnAccept(int fd, SocketAddress address, int uid) override;
+	void OnAccept(UniqueSocketDescriptor &&fd,
+		      SocketAddress address, int uid) override;
 };
 
 extern const class Domain httpd_output_domain;
diff --git a/src/output/plugins/httpd/HttpdOutputPlugin.cxx b/src/output/plugins/httpd/HttpdOutputPlugin.cxx
index 216061e53..2f876de62 100644
--- a/src/output/plugins/httpd/HttpdOutputPlugin.cxx
+++ b/src/output/plugins/httpd/HttpdOutputPlugin.cxx
@@ -25,6 +25,7 @@
 #include "encoder/EncoderInterface.hxx"
 #include "encoder/EncoderPlugin.hxx"
 #include "encoder/EncoderList.hxx"
+#include "net/UniqueSocketDescriptor.hxx"
 #include "net/SocketAddress.hxx"
 #include "net/ToString.hxx"
 #include "Page.hxx"
@@ -118,9 +119,9 @@ HttpdOutput::Unbind()
  * HttpdOutput.clients linked list.
  */
 inline void
-HttpdOutput::AddClient(SocketDescriptor fd)
+HttpdOutput::AddClient(UniqueSocketDescriptor &&fd)
 {
-	auto *client = new HttpdClient(*this, fd, GetEventLoop(),
+	auto *client = new HttpdClient(*this, std::move(fd), GetEventLoop(),
 				       !encoder->ImplementsTag());
 	clients.push_front(*client);
 
@@ -151,7 +152,8 @@ HttpdOutput::RunDeferred()
 }
 
 void
-HttpdOutput::OnAccept(int fd, SocketAddress address, gcc_unused int uid)
+HttpdOutput::OnAccept(UniqueSocketDescriptor &&fd,
+		      SocketAddress address, gcc_unused int uid)
 {
 	/* the listener socket has become readable - a client has
 	   connected */
@@ -163,7 +165,7 @@ HttpdOutput::OnAccept(int fd, SocketAddress address, gcc_unused int uid)
 		const char *progname = "mpd";
 
 		struct request_info req;
-		request_init(&req, RQ_FILE, fd, RQ_DAEMON, progname, 0);
+		request_init(&req, RQ_FILE, fd.Get(), RQ_DAEMON, progname, 0);
 
 		fromhost(&req);
 
@@ -172,7 +174,6 @@ HttpdOutput::OnAccept(int fd, SocketAddress address, gcc_unused int uid)
 			FormatWarning(httpd_output_domain,
 				      "libwrap refused connection (libwrap=%s) from %s",
 				      progname, hostaddr.c_str());
-			close_socket(fd);
 			return;
 		}
 	}
@@ -184,9 +185,7 @@ HttpdOutput::OnAccept(int fd, SocketAddress address, gcc_unused int uid)
 
 	/* can we allow additional client */
 	if (open && (clients_max == 0 || clients.size() < clients_max))
-		AddClient(SocketDescriptor(fd));
-	else
-		close_socket(fd);
+		AddClient(std::move(fd));
 }
 
 PagePtr