diff --git a/src/output/Internal.cxx b/src/output/Internal.cxx
index 5fe77584c..d02801a39 100644
--- a/src/output/Internal.cxx
+++ b/src/output/Internal.cxx
@@ -108,8 +108,6 @@ AudioOutput::CloseFilter() noexcept
 void
 AudioOutput::Close(bool drain) noexcept
 {
-	const ScopeUnlock unlock(mutex);
-
 	CloseOutput(drain);
 	CloseFilter();
 
diff --git a/src/output/Internal.hxx b/src/output/Internal.hxx
index f39355192..0bcb23e39 100644
--- a/src/output/Internal.hxx
+++ b/src/output/Internal.hxx
@@ -142,6 +142,11 @@ public:
 
 	void Disable() noexcept;
 
+	/**
+	 * Invoke OutputPlugin::close().
+	 *
+	 * Caller must not lock the mutex.
+	 */
 	void Close(bool drain) noexcept;
 
 	/**
diff --git a/src/output/Thread.cxx b/src/output/Thread.cxx
index 015f37035..70608809a 100644
--- a/src/output/Thread.cxx
+++ b/src/output/Thread.cxx
@@ -87,7 +87,12 @@ AudioOutputControl::InternalOpen2(const AudioFormat in_audio_format)
 					   output->out_audio_format);
 		} catch (const std::runtime_error &e) {
 			open = false;
-			output->Close(false);
+
+			{
+				const ScopeUnlock unlock(mutex);
+				output->Close(false);
+			}
+
 			std::throw_with_nested(FormatRuntimeError("Failed to convert for \"%s\" [%s]",
 								  GetName(), output->plugin.name));
 		}
@@ -194,7 +199,12 @@ AudioOutputControl::InternalClose(bool drain) noexcept
 	assert(IsOpen());
 
 	open = false;
-	output->Close(drain);
+
+	{
+		const ScopeUnlock unlock(mutex);
+		output->Close(drain);
+	}
+
 	source.Close();
 }