diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 77ff21128..92794f4a2 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -60,7 +60,7 @@ void LogSettings() {
     log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue());
     log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
     log_setting("Renderer_AsyncASTC", values.async_astc.GetValue());
-    log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
+    log_setting("Renderer_UseVsync", values.vsync_mode.GetValue());
     log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
     log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
     log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
@@ -222,7 +222,6 @@ void RestoreGlobalState(bool is_powered_on) {
     values.nvdec_emulation.SetGlobal(true);
     values.accelerate_astc.SetGlobal(true);
     values.async_astc.SetGlobal(true);
-    values.use_vsync.SetGlobal(true);
     values.shader_backend.SetGlobal(true);
     values.use_asynchronous_shaders.SetGlobal(true);
     values.use_fast_gpu_time.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 5379d0dd5..2371495e4 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -16,6 +16,12 @@
 
 namespace Settings {
 
+enum class VSyncMode : u32 {
+    Immediate,
+    FIFO,
+    Mailbox,
+};
+
 enum class RendererBackend : u32 {
     OpenGL = 0,
     Vulkan = 1,
@@ -455,7 +461,8 @@ struct Values {
     SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
     SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
     SwitchableSetting<bool> async_astc{false, "async_astc"};
-    SwitchableSetting<bool> use_vsync{true, "use_vsync"};
+    Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate, VSyncMode::Mailbox,
+                                        "use_vsync"};
     SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL,
                                                           ShaderBackend::SPIRV, "shader_backend"};
     SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 9178b00ca..6ec8e440c 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -85,6 +85,18 @@ static const char* TranslateNvdecEmulation(Settings::NvdecEmulation backend) {
     return "Unknown";
 }
 
+constexpr const char* TranslateVSyncMode(Settings::VSyncMode mode) {
+    switch (mode) {
+    case Settings::VSyncMode::Immediate:
+        return "Immediate";
+    case Settings::VSyncMode::FIFO:
+        return "FIFO";
+    case Settings::VSyncMode::Mailbox:
+        return "Mailbox";
+    }
+    return "Unknown";
+}
+
 u64 GetTelemetryId() {
     u64 telemetry_id{};
     const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id";
@@ -241,7 +253,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
     AddField(field_type, "Renderer_NvdecEmulation",
              TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue()));
     AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue());
-    AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
+    AddField(field_type, "Renderer_UseVsync",
+             TranslateVSyncMode(Settings::values.vsync_mode.GetValue()));
     AddField(field_type, "Renderer_ShaderBackend",
              static_cast<u32>(Settings::values.shader_backend.GetValue()));
     AddField(field_type, "Renderer_UseAsynchronousShaders",
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 23bbea7f1..08d82769c 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -34,21 +34,22 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats)
 }
 
 VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) {
-    // Mailbox (triple buffering) doesn't lock the application like fifo (vsync),
-    // prefer it if vsync option is not selected
-    const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR);
-    if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Borderless &&
-        found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) {
+    // Mailbox (triple buffering) doesn't lock the application like FIFO (vsync)
+    // FIFO present mode locks the framerate to the monitor's refresh rate
+    const bool has_mailbox =
+        std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != modes.end();
+    const bool has_imm =
+        std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != modes.end();
+    const Settings::VSyncMode mode = Settings::values.vsync_mode.GetValue();
+
+    if (mode == Settings::VSyncMode::Immediate && has_imm) {
+        LOG_INFO(Render_Vulkan, "Using swap present mode Immediate");
+        return VK_PRESENT_MODE_IMMEDIATE_KHR;
+    } else if (mode == Settings::VSyncMode::Mailbox && has_mailbox) {
+        LOG_INFO(Render_Vulkan, "Using swap present mode Mailbox");
         return VK_PRESENT_MODE_MAILBOX_KHR;
     }
-    if (!Settings::values.use_speed_limit.GetValue()) {
-        // FIFO present mode locks the framerate to the monitor's refresh rate,
-        // Find an alternative to surpass this limitation if FPS is unlocked.
-        const auto found_imm = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR);
-        if (found_imm != modes.end()) {
-            return VK_PRESENT_MODE_IMMEDIATE_KHR;
-        }
-    }
+    LOG_INFO(Render_Vulkan, "Using swap present mode FIFO");
     return VK_PRESENT_MODE_FIFO_KHR;
 }
 
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 4c7bf28d8..01dc51cff 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -154,7 +154,18 @@ public:
 
         // disable vsync for any shared contexts
         auto format = share_context->format();
-        format.setSwapInterval(main_surface ? Settings::values.use_vsync.GetValue() : 0);
+        const int swap_interval = [&]() {
+            switch (Settings::values.vsync_mode.GetValue()) {
+            case Settings::VSyncMode::Immediate:
+                return 0;
+            case Settings::VSyncMode::FIFO:
+                return 1;
+            case Settings::VSyncMode::Mailbox:
+                return 2;
+            }
+        }();
+
+        format.setSwapInterval(main_surface ? swap_interval : 0);
 
         context = std::make_unique<QOpenGLContext>();
         context->setShareContext(share_context);
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 305891d18..4a8436e5c 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -6,6 +6,7 @@
 #include <QSettings>
 #include "common/fs/fs.h"
 #include "common/fs/path_util.h"
+#include "common/settings.h"
 #include "core/core.h"
 #include "core/hle/service/acc/profile_manager.h"
 #include "core/hle/service/hid/controllers/npad.h"
@@ -709,7 +710,6 @@ void Config::ReadRendererValues() {
     ReadGlobalSetting(Settings::values.nvdec_emulation);
     ReadGlobalSetting(Settings::values.accelerate_astc);
     ReadGlobalSetting(Settings::values.async_astc);
-    ReadGlobalSetting(Settings::values.use_vsync);
     ReadGlobalSetting(Settings::values.shader_backend);
     ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
     ReadGlobalSetting(Settings::values.use_fast_gpu_time);
@@ -720,6 +720,10 @@ void Config::ReadRendererValues() {
     ReadGlobalSetting(Settings::values.bg_blue);
 
     if (global) {
+        Settings::values.vsync_mode.SetValue(static_cast<Settings::VSyncMode>(
+            ReadSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()),
+                        static_cast<u32>(Settings::values.vsync_mode.GetDefault()))
+                .value<u32>()));
         ReadBasicSetting(Settings::values.renderer_debug);
         ReadBasicSetting(Settings::values.renderer_shader_feedback);
         ReadBasicSetting(Settings::values.enable_nsight_aftermath);
@@ -1352,7 +1356,6 @@ void Config::SaveRendererValues() {
                  Settings::values.nvdec_emulation.UsingGlobal());
     WriteGlobalSetting(Settings::values.accelerate_astc);
     WriteGlobalSetting(Settings::values.async_astc);
-    WriteGlobalSetting(Settings::values.use_vsync);
     WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()),
                  static_cast<u32>(Settings::values.shader_backend.GetValue(global)),
                  static_cast<u32>(Settings::values.shader_backend.GetDefault()),
@@ -1366,6 +1369,9 @@ void Config::SaveRendererValues() {
     WriteGlobalSetting(Settings::values.bg_blue);
 
     if (global) {
+        WriteSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()),
+                     static_cast<u32>(Settings::values.vsync_mode.GetValue()),
+                     static_cast<u32>(Settings::values.vsync_mode.GetDefault()));
         WriteBasicSetting(Settings::values.renderer_debug);
         WriteBasicSetting(Settings::values.renderer_shader_feedback);
         WriteBasicSetting(Settings::values.enable_nsight_aftermath);
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index e9388daad..17a54f0f4 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -99,6 +99,7 @@ void ConfigureGraphics::SetConfiguration() {
     ui->nvdec_emulation_widget->setEnabled(runtime_lock);
     ui->resolution_combobox->setEnabled(runtime_lock);
     ui->accelerate_astc->setEnabled(runtime_lock);
+    ui->vsync_mode_combobox->setEnabled(runtime_lock);
     ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
     ui->use_asynchronous_gpu_emulation->setChecked(
         Settings::values.use_asynchronous_gpu_emulation.GetValue());
@@ -118,6 +119,9 @@ void ConfigureGraphics::SetConfiguration() {
         ui->fsr_sharpening_slider->setValue(Settings::values.fsr_sharpening_slider.GetValue());
         ui->anti_aliasing_combobox->setCurrentIndex(
             static_cast<int>(Settings::values.anti_aliasing.GetValue()));
+
+        ui->vsync_mode_combobox->setCurrentIndex(
+            static_cast<int>(Settings::values.vsync_mode.GetValue()));
     } else {
         ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
         ConfigurationShared::SetHighlight(ui->api_widget,
@@ -232,6 +236,9 @@ void ConfigureGraphics::ApplyConfiguration() {
             Settings::values.anti_aliasing.SetValue(anti_aliasing);
         }
         Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value());
+
+        Settings::values.vsync_mode.SetValue(
+            static_cast<Settings::VSyncMode>(ui->vsync_mode_combobox->currentIndex()));
     } else {
         if (ui->resolution_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
             Settings::values.resolution_setup.SetGlobal(true);
@@ -465,4 +472,6 @@ void ConfigureGraphics::SetupPerGameUI() {
         ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
     ConfigurationShared::InsertGlobalItem(
         ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true)));
+
+    ui->vsync_mode_layout->setVisible(false);
 }
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index a45ec69ec..4c241e247 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -188,6 +188,53 @@
           </property>
          </widget>
         </item>
+        <item>
+         <widget class="QWidget" name="vsync_mode_layout" native="true">
+          <layout class="QHBoxLayout" name="horizontalLayout_4">
+           <property name="leftMargin">
+            <number>0</number>
+           </property>
+           <property name="topMargin">
+            <number>0</number>
+           </property>
+           <property name="rightMargin">
+            <number>0</number>
+           </property>
+           <property name="bottomMargin">
+            <number>0</number>
+           </property>
+           <item>
+            <widget class="QLabel" name="vsync_mode_label">
+             <property name="text">
+              <string>VSync Mode</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QComboBox" name="vsync_mode_combobox">
+             <property name="currentText">
+              <string>Off (Immediate)</string>
+             </property>
+             <item>
+              <property name="text">
+               <string>Off (Immediate)</string>
+              </property>
+             </item>
+             <item>
+              <property name="text">
+               <string>Double Buffering (FIFO)</string>
+              </property>
+             </item>
+             <item>
+              <property name="text">
+               <string>Triple Buffering (Mailbox)</string>
+              </property>
+             </item>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
         <item>
          <widget class="QWidget" name="nvdec_emulation_widget" native="true">
           <layout class="QHBoxLayout" name="nvdec_emulation_layout">
@@ -366,7 +413,7 @@
              </item>
              <item>
               <property name="text">
-                  <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string>
+               <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string>
               </property>
              </item>
              <item>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 7f7bf0e4d..4072ce145 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -21,7 +21,6 @@ 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);
@@ -30,7 +29,6 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
 
     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());
     ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
     ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
@@ -63,7 +61,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
                                              renderer_force_max_clock);
     ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
                                              ui->anisotropic_filtering_combobox);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync);
     ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc,
                                              async_astc);
     ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
@@ -97,7 +94,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
         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());
         ui->async_astc->setEnabled(Settings::values.async_astc.UsingGlobal());
         ui->use_asynchronous_shaders->setEnabled(
             Settings::values.use_asynchronous_shaders.UsingGlobal());
@@ -117,7 +113,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
     ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock,
                                             Settings::values.renderer_force_max_clock,
                                             renderer_force_max_clock);
-    ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync);
     ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc,
                                             async_astc);
     ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders,
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index d7ec18939..134023032 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -86,16 +86,6 @@
           </property>
          </widget>
         </item>
-        <item>
-         <widget class="QCheckBox" name="use_vsync">
-          <property name="toolTip">
-           <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string>
-          </property>
-          <property name="text">
-           <string>Use VSync</string>
-          </property>
-         </widget>
-        </item>
         <item>
          <widget class="QCheckBox" name="async_astc">
           <property name="toolTip">
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index fa347fb8c..a692ef809 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -320,7 +320,7 @@ void Config::ReadValues() {
     ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
     ReadSetting("Renderer", Settings::values.gpu_accuracy);
     ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
-    ReadSetting("Renderer", Settings::values.use_vsync);
+    ReadSetting("Renderer", Settings::values.vsync_mode);
     ReadSetting("Renderer", Settings::values.shader_backend);
     ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
     ReadSetting("Renderer", Settings::values.nvdec_emulation);