diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 84955030b1..77ff211283 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -205,6 +205,7 @@ void RestoreGlobalState(bool is_powered_on) {
     // Renderer
     values.fsr_sharpening_slider.SetGlobal(true);
     values.renderer_backend.SetGlobal(true);
+    values.async_presentation.SetGlobal(true);
     values.renderer_force_max_clock.SetGlobal(true);
     values.vulkan_device.SetGlobal(true);
     values.fullscreen_mode.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index b77a1580ae..5379d0dd52 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -422,6 +422,7 @@ struct Values {
     // Renderer
     SwitchableSetting<RendererBackend, true> renderer_backend{
         RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"};
+    SwitchableSetting<bool> async_presentation{false, "async_presentation"};
     SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"};
     Setting<bool> renderer_debug{false, "debug"};
     Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp
index 0b8e8ad27b..a137c66f29 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "common/microprofile.h"
+#include "common/settings.h"
 #include "common/thread.h"
 #include "video_core/renderer_vulkan/vk_present_manager.h"
 #include "video_core/renderer_vulkan/vk_scheduler.h"
@@ -97,6 +98,7 @@ PresentManager::PresentManager(Core::Frontend::EmuWindow& render_window_, const
     : render_window{render_window_}, device{device_},
       memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_},
       blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())},
+      use_present_thread{Settings::values.async_presentation.GetValue()},
       image_count{swapchain.GetImageCount()} {
 
     auto& dld = device.GetLogical();
@@ -126,7 +128,9 @@ PresentManager::PresentManager(Core::Frontend::EmuWindow& render_window_, const
         free_queue.push(&frame);
     }
 
-    present_thread = std::jthread([this](std::stop_token token) { PresentThread(token); });
+    if (use_present_thread) {
+        present_thread = std::jthread([this](std::stop_token token) { PresentThread(token); });
+    }
 }
 
 PresentManager::~PresentManager() = default;
@@ -150,6 +154,12 @@ Frame* PresentManager::GetRenderFrame() {
 }
 
 void PresentManager::PushFrame(Frame* frame) {
+    if (!use_present_thread) {
+        CopyToSwapchain(frame);
+        free_queue.push(frame);
+        return;
+    }
+
     std::unique_lock lock{queue_mutex};
     present_queue.push(frame);
     frame_cv.notify_one();
@@ -227,6 +237,10 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_
 }
 
 void PresentManager::WaitPresent() {
+    if (!use_present_thread) {
+        return;
+    }
+
     // Wait for the present queue to be empty
     {
         std::unique_lock queue_lock{queue_mutex};
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h
index f5d9fc96d1..9885fd7c6f 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.h
+++ b/src/video_core/renderer_vulkan/vk_present_manager.h
@@ -75,7 +75,8 @@ private:
     std::mutex queue_mutex;
     std::mutex free_mutex;
     std::jthread present_thread;
-    bool blit_supported{};
+    bool blit_supported;
+    bool use_present_thread;
     std::size_t image_count;
 };
 
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index bb731276ed..305891d18f 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -692,6 +692,7 @@ void Config::ReadRendererValues() {
     qt_config->beginGroup(QStringLiteral("Renderer"));
 
     ReadGlobalSetting(Settings::values.renderer_backend);
+    ReadGlobalSetting(Settings::values.async_presentation);
     ReadGlobalSetting(Settings::values.renderer_force_max_clock);
     ReadGlobalSetting(Settings::values.vulkan_device);
     ReadGlobalSetting(Settings::values.fullscreen_mode);
@@ -1313,6 +1314,7 @@ void Config::SaveRendererValues() {
                  static_cast<u32>(Settings::values.renderer_backend.GetValue(global)),
                  static_cast<u32>(Settings::values.renderer_backend.GetDefault()),
                  Settings::values.renderer_backend.UsingGlobal());
+    WriteGlobalSetting(Settings::values.async_presentation);
     WriteGlobalSetting(Settings::values.renderer_force_max_clock);
     WriteGlobalSetting(Settings::values.vulkan_device);
     WriteSetting(QString::fromStdString(Settings::values.fullscreen_mode.GetLabel()),
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 59fb1b3343..7f7bf0e4d0 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -22,11 +22,13 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
 void ConfigureGraphicsAdvanced::SetConfiguration() {
     const bool runtime_lock = !system.IsPoweredOn();
     ui->use_vsync->setEnabled(runtime_lock);
+    ui->async_present->setEnabled(runtime_lock);
     ui->renderer_force_max_clock->setEnabled(runtime_lock);
     ui->async_astc->setEnabled(runtime_lock);
     ui->use_asynchronous_shaders->setEnabled(runtime_lock);
     ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
 
+    ui->async_present->setChecked(Settings::values.async_presentation.GetValue());
     ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue());
     ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
     ui->async_astc->setChecked(Settings::values.async_astc.GetValue());
@@ -54,6 +56,8 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
 
 void ConfigureGraphicsAdvanced::ApplyConfiguration() {
     ConfigurationShared::ApplyPerGameSetting(&Settings::values.gpu_accuracy, ui->gpu_accuracy);
+    ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_presentation,
+                                             ui->async_present, async_present);
     ConfigurationShared::ApplyPerGameSetting(&Settings::values.renderer_force_max_clock,
                                              ui->renderer_force_max_clock,
                                              renderer_force_max_clock);
@@ -90,6 +94,7 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
     // Disable if not global (only happens during game)
     if (Settings::IsConfiguringGlobal()) {
         ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
+        ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal());
         ui->renderer_force_max_clock->setEnabled(
             Settings::values.renderer_force_max_clock.UsingGlobal());
         ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal());
@@ -107,6 +112,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
         return;
     }
 
+    ConfigurationShared::SetColoredTristate(ui->async_present, Settings::values.async_presentation,
+                                            async_present);
     ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock,
                                             Settings::values.renderer_force_max_clock,
                                             renderer_force_max_clock);
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index bf1b047491..5394ed40aa 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -36,6 +36,7 @@ private:
 
     std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
 
+    ConfigurationShared::CheckState async_present;
     ConfigurationShared::CheckState renderer_force_max_clock;
     ConfigurationShared::CheckState use_vsync;
     ConfigurationShared::CheckState async_astc;
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index a7dbdc18cf..d7ec189395 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>404</width>
-    <height>321</height>
+    <height>376</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -69,6 +69,13 @@
           </layout>
          </widget>
         </item>
+        <item>
+         <widget class="QCheckBox" name="async_present">
+          <property name="text">
+           <string>Enable asynchronous presentation (Vulkan only)</string>
+          </property>
+         </widget>
+        </item>
         <item>
          <widget class="QCheckBox" name="renderer_force_max_clock">
           <property name="toolTip">
@@ -112,7 +119,7 @@
         <item>
          <widget class="QCheckBox" name="use_fast_gpu_time">
           <property name="toolTip">
-            <string>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</string>
+           <string>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</string>
           </property>
           <property name="text">
            <string>Use Fast GPU Time (Hack)</string>
@@ -122,7 +129,7 @@
         <item>
          <widget class="QCheckBox" name="use_pessimistic_flushes">
           <property name="toolTip">
-            <string>Enables pessimistic buffer flushes. This option will force unmodified buffers to be flushed, which can cost performance.</string>
+           <string>Enables pessimistic buffer flushes. This option will force unmodified buffers to be flushed, which can cost performance.</string>
           </property>
           <property name="text">
            <string>Use pessimistic buffer flushes (Hack)</string>
@@ -132,7 +139,7 @@
         <item>
          <widget class="QCheckBox" name="use_vulkan_driver_pipeline_cache">
           <property name="toolTip">
-            <string>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally.</string>
+           <string>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally.</string>
           </property>
           <property name="text">
            <string>Use Vulkan pipeline cache</string>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 464da32316..fa347fb8cb 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -300,6 +300,7 @@ void Config::ReadValues() {
 
     // Renderer
     ReadSetting("Renderer", Settings::values.renderer_backend);
+    ReadSetting("Renderer", Settings::values.async_presentation);
     ReadSetting("Renderer", Settings::values.renderer_force_max_clock);
     ReadSetting("Renderer", Settings::values.renderer_debug);
     ReadSetting("Renderer", Settings::values.renderer_shader_feedback);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 209cfc28ae..c0c89fbb9b 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -264,6 +264,10 @@ cpuopt_unsafe_ignore_global_monitor =
 # 0: OpenGL, 1 (default): Vulkan
 backend =
 
+# Whether to enable asynchronous presentation (Vulkan only)
+# 0 (default): Off, 1: On
+async_presentation =
+
 # Enable graphics API debugging mode.
 # 0 (default): Disabled, 1: Enabled
 debug =