diff --git a/src/Permission.cxx b/src/Permission.cxx
index a04af97ec..cfacdbffd 100644
--- a/src/Permission.cxx
+++ b/src/Permission.cxx
@@ -33,7 +33,7 @@ static constexpr struct {
 	{ nullptr, 0 },
 };
 
-static std::map<std::string, unsigned> permission_passwords;
+static std::map<std::string, unsigned, std::less<>> permission_passwords;
 
 static unsigned permission_default;
 
@@ -42,7 +42,7 @@ static unsigned local_permissions;
 #endif
 
 #ifdef HAVE_TCP
-static std::map<std::string, unsigned> host_passwords;
+static std::map<std::string, unsigned, std::less<>> host_passwords;
 #endif
 
 static unsigned
diff --git a/src/client/Client.hxx b/src/client/Client.hxx
index 96543bb0d..b0f6514c3 100644
--- a/src/client/Client.hxx
+++ b/src/client/Client.hxx
@@ -88,7 +88,7 @@ private:
 	/**
 	 * A list of channel names this client is subscribed to.
 	 */
-	std::set<std::string> subscriptions;
+	std::set<std::string, std::less<>> subscriptions;
 
 	/**
 	 * The number of subscriptions in #subscriptions.  Used to
diff --git a/src/command/MessageCommands.cxx b/src/command/MessageCommands.cxx
index ccbcaae3b..b3d1b9673 100644
--- a/src/command/MessageCommands.cxx
+++ b/src/command/MessageCommands.cxx
@@ -61,7 +61,7 @@ handle_channels(Client &client, [[maybe_unused]] Request args, Response &r)
 {
 	assert(args.empty());
 
-	std::set<std::string> channels;
+	std::set<std::string, std::less<>> channels;
 
 	for (const auto &c : client.GetPartition().clients) {
 		const auto &subscriptions = c.GetSubscriptions();
diff --git a/src/db/Count.cxx b/src/db/Count.cxx
index 4997c8390..b1b574ded 100644
--- a/src/db/Count.cxx
+++ b/src/db/Count.cxx
@@ -24,7 +24,7 @@ struct SearchStats {
 		: total_duration(0) {}
 };
 
-class TagCountMap : public std::map<std::string, SearchStats> {
+class TagCountMap : public std::map<std::string, SearchStats, std::less<>> {
 };
 
 static void
diff --git a/src/decoder/DecoderPlugin.hxx b/src/decoder/DecoderPlugin.hxx
index 49697415b..67b838952 100644
--- a/src/decoder/DecoderPlugin.hxx
+++ b/src/decoder/DecoderPlugin.hxx
@@ -38,7 +38,7 @@ struct DecoderPlugin {
 	/**
 	 * Return a set of supported protocols.
 	 */
-	std::set<std::string> (*protocols)() noexcept = nullptr;
+	std::set<std::string, std::less<>> (*protocols)() noexcept = nullptr;
 
 	/**
 	 * Decode an URI with a protocol listed in protocols().
@@ -138,7 +138,7 @@ struct DecoderPlugin {
 		return copy;
 	}
 
-	constexpr auto WithProtocols(std::set<std::string> (*_protocols)() noexcept,
+	constexpr auto WithProtocols(std::set<std::string, std::less<>> (*_protocols)() noexcept,
 				     void (*_uri_decode)(DecoderClient &client, const char *uri)) const noexcept {
 		auto copy = *this;
 		copy.protocols = _protocols;
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index b0142806c..a327ded74 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -672,10 +672,10 @@ ffmpeg_uri_decode(DecoderClient &client, const char *uri)
 	FfmpegDecode(client, nullptr, *format_context);
 }
 
-static std::set<std::string>
+static std::set<std::string, std::less<>>
 ffmpeg_protocols() noexcept
 {
-	std::set<std::string> protocols;
+	std::set<std::string, std::less<>> protocols;
 
 	const AVInputFormat *format = nullptr;
 	void *opaque = nullptr;
diff --git a/src/input/InputPlugin.hxx b/src/input/InputPlugin.hxx
index 7c0a75387..742618e55 100644
--- a/src/input/InputPlugin.hxx
+++ b/src/input/InputPlugin.hxx
@@ -52,7 +52,7 @@ struct InputPlugin {
 	/**
 	 * return a set of supported protocols
 	 */
-	std::set<std::string> (*protocols)() noexcept;
+	std::set<std::string, std::less<>> (*protocols)() noexcept;
 
 	/**
 	 * Prepare a #RemoteTagScanner.  The operation must be started
diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx
index 409bdf88e..7045bddc1 100644
--- a/src/input/plugins/CurlInputPlugin.cxx
+++ b/src/input/plugins/CurlInputPlugin.cxx
@@ -589,10 +589,10 @@ input_curl_open(const char *url, Mutex &mutex)
 	return CurlInputStream::Open(url, {}, mutex);
 }
 
-static std::set<std::string>
+static std::set<std::string, std::less<>>
 input_curl_protocols() noexcept
 {
-	std::set<std::string> protocols;
+	std::set<std::string, std::less<>> protocols;
 	auto version_info = curl_version_info(CURLVERSION_FIRST);
 	for (auto proto_ptr = version_info->protocols; *proto_ptr != nullptr; proto_ptr++) {
 		if (protocol_is_whitelisted(*proto_ptr)) {
diff --git a/src/input/plugins/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx
index 91e91c3c1..90c0135eb 100644
--- a/src/input/plugins/FfmpegInputPlugin.cxx
+++ b/src/input/plugins/FfmpegInputPlugin.cxx
@@ -57,12 +57,12 @@ input_ffmpeg_init(EventLoop &, const ConfigBlock &)
 		throw PluginUnavailable("No protocol");
 }
 
-static std::set<std::string>
+static std::set<std::string, std::less<>>
 input_ffmpeg_protocols() noexcept
 {
 	void *opaque = nullptr;
 	const char* protocol;
-	std::set<std::string> protocols;
+	std::set<std::string, std::less<>> protocols;
 	while ((protocol = avio_enum_protocols(&opaque, 0))) {
 		if (StringIsEqual(protocol, "hls")) {
 			/* just "hls://" doesn't work, but these do
diff --git a/src/ls.cxx b/src/ls.cxx
index b969292b4..cf98a4676 100644
--- a/src/ls.cxx
+++ b/src/ls.cxx
@@ -20,7 +20,7 @@ void print_supported_uri_schemes_to_fp(FILE *fp)
 #ifdef HAVE_UN
 	fprintf(fp, " file://");
 #endif
-	std::set<std::string> protocols;
+	std::set<std::string, std::less<>> protocols;
 	input_plugins_for_each(plugin)
 		plugin->ForeachSupportedUri([&](const char* uri) {
 			protocols.emplace(uri);
@@ -40,7 +40,7 @@ void print_supported_uri_schemes_to_fp(FILE *fp)
 void
 print_supported_uri_schemes(Response &r)
 {
-	std::set<std::string> protocols;
+	std::set<std::string, std::less<>> protocols;
 	input_plugins_for_each_enabled(plugin)
 		plugin->ForeachSupportedUri([&](const char* uri) {
 			protocols.emplace(uri);
diff --git a/src/neighbor/plugins/UdisksNeighborPlugin.cxx b/src/neighbor/plugins/UdisksNeighborPlugin.cxx
index f18b8e012..4a59e5941 100644
--- a/src/neighbor/plugins/UdisksNeighborPlugin.cxx
+++ b/src/neighbor/plugins/UdisksNeighborPlugin.cxx
@@ -51,9 +51,9 @@ class UdisksNeighborExplorer final
 	 */
 	mutable Mutex mutex;
 
-	using ByUri = std::map<std::string, NeighborInfo>;
+	using ByUri = std::map<std::string, NeighborInfo, std::less<>>;
 	ByUri by_uri;
-	std::map<std::string, ByUri::iterator> by_path;
+	std::map<std::string, ByUri::iterator, std::less<>> by_path;
 
 public:
 	UdisksNeighborExplorer(EventLoop &_event_loop,
diff --git a/src/output/Control.cxx b/src/output/Control.cxx
index a9cd5106e..620b9c177 100644
--- a/src/output/Control.cxx
+++ b/src/output/Control.cxx
@@ -103,12 +103,12 @@ AudioOutputControl::GetMixer() const noexcept
 	return output ? output->mixer : nullptr;
 }
 
-std::map<std::string, std::string>
+std::map<std::string, std::string, std::less<>>
 AudioOutputControl::GetAttributes() const noexcept
 {
 	return output
 		? output->GetAttributes()
-		: std::map<std::string, std::string>{};
+		: std::map<std::string, std::string, std::less<>>{};
 }
 
 void
diff --git a/src/output/Control.hxx b/src/output/Control.hxx
index 761068021..b28a32ae9 100644
--- a/src/output/Control.hxx
+++ b/src/output/Control.hxx
@@ -371,7 +371,7 @@ public:
 
 	void BeginDestroy() noexcept;
 
-	std::map<std::string, std::string> GetAttributes() const noexcept;
+	std::map<std::string, std::string, std::less<>> GetAttributes() const noexcept;
 	void SetAttribute(std::string &&name, std::string &&value);
 
 	/**
diff --git a/src/output/Filtered.cxx b/src/output/Filtered.cxx
index 9ac0b0055..747e12c18 100644
--- a/src/output/Filtered.cxx
+++ b/src/output/Filtered.cxx
@@ -33,7 +33,7 @@ FilteredAudioOutput::SupportsPause() const noexcept
 	return output->SupportsPause();
 }
 
-std::map<std::string, std::string>
+std::map<std::string, std::string, std::less<>>
 FilteredAudioOutput::GetAttributes() const noexcept
 {
 	return output->GetAttributes();
diff --git a/src/output/Filtered.hxx b/src/output/Filtered.hxx
index 37e08f4f5..e9c4b2780 100644
--- a/src/output/Filtered.hxx
+++ b/src/output/Filtered.hxx
@@ -155,7 +155,7 @@ public:
 	[[gnu::pure]]
 	bool SupportsPause() const noexcept;
 
-	std::map<std::string, std::string> GetAttributes() const noexcept;
+	std::map<std::string, std::string, std::less<>> GetAttributes() const noexcept;
 	void SetAttribute(std::string &&name, std::string &&value);
 
 	/**
diff --git a/src/output/Interface.hxx b/src/output/Interface.hxx
index 1a2f5765d..8c679f66c 100644
--- a/src/output/Interface.hxx
+++ b/src/output/Interface.hxx
@@ -49,7 +49,7 @@ public:
 	 *
 	 * This method must be thread-safe.
 	 */
-	virtual std::map<std::string, std::string> GetAttributes() const noexcept {
+	virtual std::map<std::string, std::string, std::less<>> GetAttributes() const noexcept {
 		return {};
 	}
 
diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx
index 3e3a6beb4..257f1cd5a 100644
--- a/src/output/plugins/AlsaOutputPlugin.cxx
+++ b/src/output/plugins/AlsaOutputPlugin.cxx
@@ -257,7 +257,7 @@ public:
 	}
 
 private:
-	std::map<std::string, std::string> GetAttributes() const noexcept override;
+	std::map<std::string, std::string, std::less<>> GetAttributes() const noexcept override;
 	void SetAttribute(std::string &&name, std::string &&value) override;
 
 	void Enable() override;
@@ -444,7 +444,7 @@ AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block)
 		allowed_formats = Alsa::AllowedFormat::ParseList(allowed_formats_string);
 }
 
-std::map<std::string, std::string>
+std::map<std::string, std::string, std::less<>>
 AlsaOutput::GetAttributes() const noexcept
 {
 	const std::scoped_lock<Mutex> lock(attributes_mutex);
diff --git a/src/sticker/Database.cxx b/src/sticker/Database.cxx
index 33a99a7f0..f6cf0486d 100644
--- a/src/sticker/Database.cxx
+++ b/src/sticker/Database.cxx
@@ -129,7 +129,7 @@ StickerDatabase::LoadValue(const char *type, const char *uri, const char *name)
 }
 
 void
-StickerDatabase::ListValues(std::map<std::string, std::string> &table,
+StickerDatabase::ListValues(std::map<std::string, std::string, std::less<>> &table,
 			    const char *type, const char *uri)
 {
 	sqlite3_stmt *const s = stmt[STICKER_SQL_LIST];
diff --git a/src/sticker/Database.hxx b/src/sticker/Database.hxx
index 2dad62035..8b59e0c93 100644
--- a/src/sticker/Database.hxx
+++ b/src/sticker/Database.hxx
@@ -127,7 +127,7 @@ public:
 		  void *user_data);
 
 private:
-	void ListValues(std::map<std::string, std::string> &table,
+	void ListValues(std::map<std::string, std::string, std::less<>> &table,
 			const char *type, const char *uri);
 
 	bool UpdateValue(const char *type, const char *uri,
diff --git a/src/sticker/Sticker.hxx b/src/sticker/Sticker.hxx
index efbb9c040..32c89a2c9 100644
--- a/src/sticker/Sticker.hxx
+++ b/src/sticker/Sticker.hxx
@@ -8,7 +8,7 @@
 #include <string>
 
 struct Sticker {
-	std::map<std::string, std::string> table;
+	std::map<std::string, std::string, std::less<>> table;
 };
 
 #endif
diff --git a/src/storage/CompositeStorage.cxx b/src/storage/CompositeStorage.cxx
index cb5c8f1dd..d7f87c54c 100644
--- a/src/storage/CompositeStorage.cxx
+++ b/src/storage/CompositeStorage.cxx
@@ -20,8 +20,8 @@
 class CompositeDirectoryReader final : public StorageDirectoryReader {
 	std::unique_ptr<StorageDirectoryReader> other;
 
-	std::set<std::string> names;
-	std::set<std::string>::const_iterator current, next;
+	std::set<std::string, std::less<>> names;
+	std::set<std::string, std::less<>>::const_iterator current, next;
 
 public:
 	template<typename O, typename M>
diff --git a/src/util/MimeType.cxx b/src/util/MimeType.cxx
index 6c7d10cda..d8f3a9202 100644
--- a/src/util/MimeType.cxx
+++ b/src/util/MimeType.cxx
@@ -12,13 +12,13 @@ GetMimeTypeBase(std::string_view s) noexcept
 	return Split(s, ';').first;
 }
 
-std::map<std::string, std::string>
+std::map<std::string, std::string, std::less<>>
 ParseMimeTypeParameters(std::string_view mime_type) noexcept
 {
 	/* discard the first segment (the base MIME type) */
 	const auto params = Split(mime_type, ';').second;
 
-	std::map<std::string, std::string> result;
+	std::map<std::string, std::string, std::less<>> result;
 	for (const std::string_view i : IterableSplitString(params, ';')) {
 		const auto s = Split(Strip(i), '=');
 		if (!s.first.empty() && s.second.data() != nullptr)
diff --git a/src/util/MimeType.hxx b/src/util/MimeType.hxx
index 6b118d177..9b42a573e 100644
--- a/src/util/MimeType.hxx
+++ b/src/util/MimeType.hxx
@@ -23,7 +23,7 @@ GetMimeTypeBase(std::string_view s) noexcept;
  *
  * "foo/bar; param1=value1; param2=value2"
  */
-std::map<std::string, std::string>
+std::map<std::string, std::string, std::less<>>
 ParseMimeTypeParameters(std::string_view mime_type) noexcept;
 
 #endif