diff --git a/src/client/Client.hxx b/src/client/Client.hxx
index 56cd947ff..849a11ed4 100644
--- a/src/client/Client.hxx
+++ b/src/client/Client.hxx
@@ -27,6 +27,8 @@
 #include "event/TimeoutMonitor.hxx"
 #include "Compiler.h"
 
+#include <boost/intrusive/list.hpp>
+
 #include <set>
 #include <string>
 #include <list>
@@ -41,12 +43,20 @@ struct Partition;
 class Database;
 class Storage;
 
-class Client final : private FullyBufferedSocket, TimeoutMonitor {
+class Client final
+	: FullyBufferedSocket, TimeoutMonitor,
+	  public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
 public:
 	Partition &partition;
 	struct playlist &playlist;
 	struct PlayerControl &player_control;
 
+	struct Disposer {
+		void operator()(Client *client) const {
+			delete client;
+		}
+	};
+
 	unsigned permission;
 
 	/** the uid of the client process, or -1 if unknown */
diff --git a/src/client/ClientList.cxx b/src/client/ClientList.cxx
index 101802479..a1f286928 100644
--- a/src/client/ClientList.cxx
+++ b/src/client/ClientList.cxx
@@ -28,28 +28,15 @@
 void
 ClientList::Remove(Client &client)
 {
-	assert(size > 0);
 	assert(!list.empty());
 
-	auto i = std::find(list.begin(), list.end(), &client);
-	assert(i != list.end());
-	list.erase(i);
-	--size;
+	list.erase(list.iterator_to(client));
 }
 
 void
 ClientList::CloseAll()
 {
-	while (!list.empty()) {
-		delete list.front();
-		list.pop_front();
-
-#ifndef NDEBUG
-		--size;
-#endif
-	}
-
-	assert(size == 0);
+	list.clear_and_dispose(Client::Disposer());
 }
 
 void
@@ -57,6 +44,6 @@ ClientList::IdleAdd(unsigned flags)
 {
 	assert(flags != 0);
 
-	for (const auto &client : list)
-		client->IdleAdd(flags);
+	for (auto &client : list)
+		client.IdleAdd(flags);
 }
diff --git a/src/client/ClientList.hxx b/src/client/ClientList.hxx
index 4d9a96dcb..7d20a8737 100644
--- a/src/client/ClientList.hxx
+++ b/src/client/ClientList.hxx
@@ -20,21 +20,21 @@
 #ifndef MPD_CLIENT_LIST_HXX
 #define MPD_CLIENT_LIST_HXX
 
-#include <list>
+#include "Client.hxx"
 
 class Client;
 
 class ClientList {
-	typedef std::list<Client *> List;
+	typedef boost::intrusive::list<Client,
+				       boost::intrusive::constant_time_size<true>> List;
 
 	const unsigned max_size;
 
-	unsigned size;
 	List list;
 
 public:
 	ClientList(unsigned _max_size)
-		:max_size(_max_size), size(0) {}
+		:max_size(_max_size) {}
 	~ClientList() {
 		CloseAll();
 	}
@@ -48,12 +48,11 @@ public:
 	}
 
 	bool IsFull() const {
-		return size >= max_size;
+		return list.size() >= max_size;
 	}
 
 	void Add(Client &client) {
-		list.push_front(&client);
-		++size;
+		list.push_front(client);
 	}
 
 	void Remove(Client &client);
diff --git a/src/command/MessageCommands.cxx b/src/command/MessageCommands.cxx
index fe7500aaf..02b251b9a 100644
--- a/src/command/MessageCommands.cxx
+++ b/src/command/MessageCommands.cxx
@@ -82,8 +82,8 @@ handle_channels(Client &client,
 
 	std::set<std::string> channels;
 	for (const auto &c : *client.partition.instance.client_list)
-		channels.insert(c->subscriptions.begin(),
-				c->subscriptions.end());
+		channels.insert(c.subscriptions.begin(),
+				c.subscriptions.end());
 
 	for (const auto &channel : channels)
 		client_printf(client, "channel: %s\n", channel.c_str());
@@ -122,8 +122,8 @@ handle_send_message(Client &client,
 
 	bool sent = false;
 	const ClientMessage msg(argv[1], argv[2]);
-	for (const auto &c : *client.partition.instance.client_list)
-		if (c->PushMessage(msg))
+	for (auto &c : *client.partition.instance.client_list)
+		if (c.PushMessage(msg))
 			sent = true;
 
 	if (sent)