diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh
index 790ba82183..6f522feed0 100755
--- a/.ci/scripts/windows/docker.sh
+++ b/.ci/scripts/windows/docker.sh
@@ -21,6 +21,7 @@ cmake .. \
     -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
     -DENABLE_QT_TRANSLATION=ON \
     -DUSE_CCACHE=ON \
+    -DYUZU_CRASH_DUMPS=ON \
     -DYUZU_USE_BUNDLED_SDL2=OFF \
     -DYUZU_USE_EXTERNAL_SDL2=OFF \
     -DYUZU_TESTS=OFF \
diff --git a/.ci/scripts/windows/upload.ps1 b/.ci/scripts/windows/upload.ps1
index d463281ded..21abcd752e 100644
--- a/.ci/scripts/windows/upload.ps1
+++ b/.ci/scripts/windows/upload.ps1
@@ -65,8 +65,8 @@ if ("$env:GITHUB_ACTIONS" -eq "true") {
     # None of the other GHA builds are including source, so commenting out today
     #Copy-Item $MSVC_SOURCE_TARXZ -Destination "artifacts"
 
-    # Are debug symbols important?
-    # cp .\build\bin\yuzu*.pdb .\pdb\
+    # Debugging symbols
+    cp .\build\bin\yuzu*.pdb .\artifacts\
 
     # Write out a tag BUILD_TAG to environment for the Upload step
     # We're getting ${{ github.event.number }} as $env:PR_NUMBER"
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml
index a2ee71bd8b..ea405e5dc6 100644
--- a/.ci/templates/build-msvc.yml
+++ b/.ci/templates/build-msvc.yml
@@ -9,7 +9,7 @@ parameters:
 steps:
 - script: choco install vulkan-sdk
   displayName: 'Install vulkan-sdk'
-- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd ..
+- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd ..
   displayName: 'Configure CMake'
 - task: MSBuild@1
   displayName: 'Build'
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index 733a52764c..7cde8380bb 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -104,7 +104,7 @@ jobs:
         run: |
           glslangValidator --version
           mkdir build
-          cmake . -B build -GNinja -DCMAKE_TOOLCHAIN_FILE="CMakeModules/MSVCCache.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_BUILD_TYPE=Release -DGIT_BRANCH=pr-verify
+          cmake . -B build -GNinja -DCMAKE_TOOLCHAIN_FILE="CMakeModules/MSVCCache.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_BUILD_TYPE=Release -DGIT_BRANCH=pr-verify -DYUZU_CRASH_DUMPS=ON
       - name: Build
         run: cmake --build build
       - name: Cache Summary
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2ab0ea589d..20dd1383f5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,8 @@ option(YUZU_USE_BUNDLED_OPUS "Compile bundled opus" ON)
 
 option(YUZU_TESTS "Compile tests" ON)
 
+CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
+
 option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
 
 option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON)
@@ -46,6 +48,9 @@ if (YUZU_USE_BUNDLED_VCPKG)
     if (YUZU_TESTS)
         list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
     endif()
+    if (YUZU_CRASH_DUMPS)
+        list(APPEND VCPKG_MANIFEST_FEATURES "dbghelp")
+    endif()
 
     include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake)
 elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "")
@@ -447,6 +452,13 @@ elseif (WIN32)
         # PSAPI is the Process Status API
         set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
     endif()
+
+    if (YUZU_CRASH_DUMPS)
+        find_library(DBGHELP_LIBRARY dbghelp)
+        if ("${DBGHELP_LIBRARY}" STREQUAL "DBGHELP_LIBRARY-NOTFOUND")
+            message(FATAL_ERROR "YUZU_CRASH_DUMPS enabled but dbghelp library not found")
+        endif()
+    endif()
 elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
     set(PLATFORM_LIBRARIES rt)
 endif()
diff --git a/src/common/settings.h b/src/common/settings.h
index 13651de575..851812f28b 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -530,6 +530,7 @@ struct Values {
     Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
     Setting<bool> use_auto_stub{false, "use_auto_stub"};
     Setting<bool> enable_all_controllers{false, "enable_all_controllers"};
+    Setting<bool> create_crash_dumps{false, "create_crash_dumps"};
 
     // Miscellaneous
     Setting<std::string> log_filter{"*:Info", "log_filter"};
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 50007338fe..29d506c472 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -208,6 +208,16 @@ add_executable(yuzu
     yuzu.rc
 )
 
+if (WIN32 AND YUZU_CRASH_DUMPS)
+    target_sources(yuzu PRIVATE
+        mini_dump.cpp
+        mini_dump.h
+    )
+
+    target_link_libraries(yuzu PRIVATE ${DBGHELP_LIBRARY})
+    target_compile_definitions(yuzu PRIVATE -DYUZU_DBGHELP)
+endif()
+
 file(GLOB COMPAT_LIST
      ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
      ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index 8be311fcbe..1d8072243b 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -63,7 +63,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
     InputCommon::InputSubsystem* input_subsystem_, Core::System& system_)
     : QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()),
       parameters(std::move(parameters_)), input_subsystem{input_subsystem_},
-      input_profiles(std::make_unique<InputProfiles>(system_)), system{system_} {
+      input_profiles(std::make_unique<InputProfiles>()), system{system_} {
     ui->setupUi(this);
 
     player_widgets = {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 8ecd87150a..a4ed684229 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -15,8 +15,7 @@
 
 namespace FS = Common::FS;
 
-Config::Config(Core::System& system_, const std::string& config_name, ConfigType config_type)
-    : type(config_type), system{system_} {
+Config::Config(const std::string& config_name, ConfigType config_type) : type(config_type) {
     global = config_type == ConfigType::GlobalConfig;
 
     Initialize(config_name);
@@ -546,6 +545,7 @@ void Config::ReadDebuggingValues() {
     ReadBasicSetting(Settings::values.use_debug_asserts);
     ReadBasicSetting(Settings::values.use_auto_stub);
     ReadBasicSetting(Settings::values.enable_all_controllers);
+    ReadBasicSetting(Settings::values.create_crash_dumps);
 
     qt_config->endGroup();
 }
@@ -1161,6 +1161,7 @@ void Config::SaveDebuggingValues() {
     WriteBasicSetting(Settings::values.use_debug_asserts);
     WriteBasicSetting(Settings::values.disable_macro_jit);
     WriteBasicSetting(Settings::values.enable_all_controllers);
+    WriteBasicSetting(Settings::values.create_crash_dumps);
 
     qt_config->endGroup();
 }
@@ -1547,7 +1548,6 @@ void Config::Reload() {
     ReadValues();
     // To apply default value changes
     SaveValues();
-    system.ApplySettings();
 }
 
 void Config::Save() {
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 486ceea949..06fa7d2d07 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -25,7 +25,7 @@ public:
         InputProfile,
     };
 
-    explicit Config(Core::System& system_, const std::string& config_name = "qt-config",
+    explicit Config(const std::string& config_name = "qt-config",
                     ConfigType config_type = ConfigType::GlobalConfig);
     ~Config();
 
@@ -194,8 +194,6 @@ private:
     std::unique_ptr<QSettings> qt_config;
     std::string qt_config_loc;
     bool global;
-
-    Core::System& system;
 };
 
 // These metatype declarations cannot be in common/settings.h because core is devoid of QT
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 04d3977509..622808e944 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include <QDesktopServices>
+#include <QMessageBox>
 #include <QUrl>
 #include "common/fs/path_util.h"
 #include "common/logging/backend.h"
@@ -26,6 +27,16 @@ ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent)
 
     connect(ui->toggle_gdbstub, &QCheckBox::toggled,
             [&]() { ui->gdbport_spinbox->setEnabled(ui->toggle_gdbstub->isChecked()); });
+
+    connect(ui->create_crash_dumps, &QCheckBox::stateChanged, [&](int) {
+        if (crash_dump_warning_shown) {
+            return;
+        }
+        QMessageBox::warning(this, tr("Restart Required"),
+                             tr("yuzu is required to restart in order to apply this setting."),
+                             QMessageBox::Ok, QMessageBox::Ok);
+        crash_dump_warning_shown = true;
+    });
 }
 
 ConfigureDebug::~ConfigureDebug() = default;
@@ -71,7 +82,14 @@ void ConfigureDebug::SetConfiguration() {
     ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue());
 #else
     ui->disable_web_applet->setEnabled(false);
-    ui->disable_web_applet->setText(QString::fromUtf8("Web applet not compiled"));
+    ui->disable_web_applet->setText(tr("Web applet not compiled"));
+#endif
+
+#ifdef YUZU_DBGHELP
+    ui->create_crash_dumps->setChecked(Settings::values.create_crash_dumps.GetValue());
+#else
+    ui->create_crash_dumps->setEnabled(false);
+    ui->create_crash_dumps->setText(tr("MiniDump creation not compiled"));
 #endif
 }
 
@@ -84,6 +102,7 @@ void ConfigureDebug::ApplyConfiguration() {
     Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked();
     Settings::values.reporting_services = ui->reporting_services->isChecked();
     Settings::values.dump_audio_commands = ui->dump_audio_commands->isChecked();
+    Settings::values.create_crash_dumps = ui->create_crash_dumps->isChecked();
     Settings::values.quest_flag = ui->quest_flag->isChecked();
     Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
     Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
diff --git a/src/yuzu/configuration/configure_debug.h b/src/yuzu/configuration/configure_debug.h
index 42d30f1709..030a0b7f75 100644
--- a/src/yuzu/configuration/configure_debug.h
+++ b/src/yuzu/configuration/configure_debug.h
@@ -32,4 +32,6 @@ private:
     std::unique_ptr<Ui::ConfigureDebug> ui;
 
     const Core::System& system;
+
+    bool crash_dump_warning_shown{false};
 };
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 47b8b80f16..314d47af5c 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -7,60 +7,60 @@
   </property>
  <widget class="QWidget">
   <layout class="QVBoxLayout" name="verticalLayout_1">
-    <item>
-      <layout class="QVBoxLayout" name="verticalLayout_2">
-       <item>
-        <widget class="QGroupBox" name="groupBox">
-         <property name="title">
-          <string>Debugger</string>
-         </property>
-         <layout class="QVBoxLayout" name="verticalLayout_3">
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout_2">
+     <item>
+      <widget class="QGroupBox" name="groupBox">
+       <property name="title">
+        <string>Debugger</string>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout_3">
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_11">
           <item>
-           <layout class="QHBoxLayout" name="horizontalLayout_11">
-            <item>
-             <widget class="QCheckBox" name="toggle_gdbstub">
-              <property name="text">
-               <string>Enable GDB Stub</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <spacer name="horizontalSpacer">
-              <property name="orientation">
-               <enum>Qt::Horizontal</enum>
-              </property>
-              <property name="sizeHint" stdset="0">
-               <size>
-                <width>40</width>
-                <height>20</height>
-               </size>
-              </property>
-             </spacer>
-            </item>
-            <item>
-             <widget class="QLabel" name="label_11">
-              <property name="text">
-               <string>Port:</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QSpinBox" name="gdbport_spinbox">
-              <property name="minimum">
-                <number>1024</number>
-              </property>
-              <property name="maximum">
-               <number>65535</number>
-              </property>
-             </widget>
-            </item>
-           </layout>
+           <widget class="QCheckBox" name="toggle_gdbstub">
+            <property name="text">
+             <string>Enable GDB Stub</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="horizontalSpacer">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_11">
+            <property name="text">
+             <string>Port:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QSpinBox" name="gdbport_spinbox">
+            <property name="minimum">
+             <number>1024</number>
+            </property>
+            <property name="maximum">
+             <number>65535</number>
+            </property>
+           </widget>
           </item>
          </layout>
-        </widget>
-       </item>
-      </layout>
+        </item>
+       </layout>
+      </widget>
      </item>
+    </layout>
+   </item>
    <item>
     <widget class="QGroupBox" name="groupBox_2">
      <property name="title">
@@ -231,6 +231,13 @@
       <string>Debugging</string>
      </property>
      <layout class="QGridLayout" name="gridLayout_3">
+      <item row="2" column="0">
+       <widget class="QCheckBox" name="reporting_services">
+        <property name="text">
+         <string>Enable Verbose Reporting Services**</string>
+        </property>
+       </widget>
+      </item>
       <item row="0" column="0">
        <widget class="QCheckBox" name="fs_access_log">
         <property name="text">
@@ -238,20 +245,20 @@
         </property>
        </widget>
       </item>
-      <item row="1" column="0">
+      <item row="0" column="1">
        <widget class="QCheckBox" name="dump_audio_commands">
-        <property name="text">
-         <string>Dump Audio Commands To Console**</string>
-        </property>
         <property name="toolTip">
          <string>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</string>
         </property>
+        <property name="text">
+         <string>Dump Audio Commands To Console**</string>
+        </property>
        </widget>
       </item>
-      <item row="2" column="0">
-       <widget class="QCheckBox" name="reporting_services">
+      <item row="2" column="1">
+       <widget class="QCheckBox" name="create_crash_dumps">
         <property name="text">
-         <string>Enable Verbose Reporting Services**</string>
+         <string>Create Minidump After Crash</string>
         </property>
        </widget>
       </item>
@@ -340,7 +347,6 @@
   <tabstop>disable_loop_safety_checks</tabstop>
   <tabstop>fs_access_log</tabstop>
   <tabstop>reporting_services</tabstop>
-  <tabstop>dump_audio_commands</tabstop>
   <tabstop>quest_flag</tabstop>
   <tabstop>enable_cpu_debugging</tabstop>
   <tabstop>use_debug_asserts</tabstop>
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 16fba3deb2..cb55472c9e 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -65,7 +65,7 @@ void OnDockedModeChanged(bool last_state, bool new_state, Core::System& system)
 
 ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent)
     : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()),
-      profiles(std::make_unique<InputProfiles>(system_)), system{system_} {
+      profiles(std::make_unique<InputProfiles>()), system{system_} {
     ui->setupUi(this);
 }
 
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index af8343b2e3..c3cb8f61d1 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -42,8 +42,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
     const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name));
     const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename())
                                                 : fmt::format("{:016X}", title_id);
-    game_config =
-        std::make_unique<Config>(system, config_file_name, Config::ConfigType::PerGameConfig);
+    game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig);
 
     addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this);
     audio_tab = std::make_unique<ConfigureAudio>(system_, this);
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp
index 20b22e7de7..807afbeb25 100644
--- a/src/yuzu/configuration/input_profiles.cpp
+++ b/src/yuzu/configuration/input_profiles.cpp
@@ -27,7 +27,7 @@ std::filesystem::path GetNameWithoutExtension(std::filesystem::path filename) {
 
 } // namespace
 
-InputProfiles::InputProfiles(Core::System& system_) : system{system_} {
+InputProfiles::InputProfiles() {
     const auto input_profile_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "input";
 
     if (!FS::IsDir(input_profile_loc)) {
@@ -43,8 +43,8 @@ InputProfiles::InputProfiles(Core::System& system_) : system{system_} {
 
             if (IsINI(filename) && IsProfileNameValid(name_without_ext)) {
                 map_profiles.insert_or_assign(
-                    name_without_ext, std::make_unique<Config>(system, name_without_ext,
-                                                               Config::ConfigType::InputProfile));
+                    name_without_ext,
+                    std::make_unique<Config>(name_without_ext, Config::ConfigType::InputProfile));
             }
 
             return true;
@@ -80,8 +80,7 @@ bool InputProfiles::CreateProfile(const std::string& profile_name, std::size_t p
     }
 
     map_profiles.insert_or_assign(
-        profile_name,
-        std::make_unique<Config>(system, profile_name, Config::ConfigType::InputProfile));
+        profile_name, std::make_unique<Config>(profile_name, Config::ConfigType::InputProfile));
 
     return SaveProfile(profile_name, player_index);
 }
diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h
index 65fc9e62c5..2bf3e42508 100644
--- a/src/yuzu/configuration/input_profiles.h
+++ b/src/yuzu/configuration/input_profiles.h
@@ -15,7 +15,7 @@ class Config;
 class InputProfiles {
 
 public:
-    explicit InputProfiles(Core::System& system_);
+    explicit InputProfiles();
     virtual ~InputProfiles();
 
     std::vector<std::string> GetInputProfileNames();
@@ -31,6 +31,4 @@ private:
     bool ProfileExistsInMap(const std::string& profile_name) const;
 
     std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles;
-
-    Core::System& system;
 };
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index a85adc0724..bda9986e12 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -138,6 +138,10 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
 #include "yuzu/uisettings.h"
 #include "yuzu/util/clickable_label.h"
 
+#ifdef YUZU_DBGHELP
+#include "yuzu/mini_dump.h"
+#endif
+
 using namespace Common::Literals;
 
 #ifdef USE_DISCORD_PRESENCE
@@ -269,10 +273,9 @@ bool GMainWindow::CheckDarkMode() {
 #endif // __linux__
 }
 
-GMainWindow::GMainWindow(bool has_broken_vulkan)
+GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan)
     : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
-      input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
-      config{std::make_unique<Config>(*system)},
+      input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)},
       vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
       provider{std::make_unique<FileSys::ManualContentProvider>()} {
 #ifdef __linux__
@@ -1637,7 +1640,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
         const auto config_file_name = title_id == 0
                                           ? Common::FS::PathToUTF8String(file_path.filename())
                                           : fmt::format("{:016X}", title_id);
-        Config per_game_config(*system, config_file_name, Config::ConfigType::PerGameConfig);
+        Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig);
+        system->ApplySettings();
     }
 
     // Save configurations
@@ -2981,7 +2985,7 @@ void GMainWindow::OnConfigure() {
 
         Settings::values.disabled_addons.clear();
 
-        config = std::make_unique<Config>(*system);
+        config = std::make_unique<Config>();
         UISettings::values.reset_to_defaults = false;
 
         UISettings::values.game_dirs = std::move(old_game_dirs);
@@ -3042,6 +3046,7 @@ void GMainWindow::OnConfigure() {
 
     UpdateStatusButtons();
     controller_dialog->refreshConfiguration();
+    system->ApplySettings();
 }
 
 void GMainWindow::OnConfigureTas() {
@@ -4082,7 +4087,24 @@ void GMainWindow::changeEvent(QEvent* event) {
 #endif
 
 int main(int argc, char* argv[]) {
+    std::unique_ptr<Config> config = std::make_unique<Config>();
     bool has_broken_vulkan = false;
+    bool is_child = false;
+    if (CheckEnvVars(&is_child)) {
+        return 0;
+    }
+
+#ifdef YUZU_DBGHELP
+    PROCESS_INFORMATION pi;
+    if (!is_child && Settings::values.create_crash_dumps.GetValue() &&
+        MiniDump::SpawnDebuggee(argv[0], pi)) {
+        // Delete the config object so that it doesn't save when the program exits
+        config.reset(nullptr);
+        MiniDump::DebugDebuggee(pi);
+        return 0;
+    }
+#endif
+
     if (StartupChecks(argv[0], &has_broken_vulkan)) {
         return 0;
     }
@@ -4135,7 +4157,7 @@ int main(int argc, char* argv[]) {
     // generating shaders
     setlocale(LC_ALL, "C");
 
-    GMainWindow main_window{has_broken_vulkan};
+    GMainWindow main_window{std::move(config), has_broken_vulkan};
     // After settings have been loaded by GMainWindow, apply the filter
     main_window.show();
 
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 1ae2b93d9b..716aef063c 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -120,7 +120,7 @@ class GMainWindow : public QMainWindow {
 public:
     void filterBarSetChecked(bool state);
     void UpdateUITheme();
-    explicit GMainWindow(bool has_broken_vulkan);
+    explicit GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan);
     ~GMainWindow() override;
 
     bool DropAction(QDropEvent* event);
diff --git a/src/yuzu/mini_dump.cpp b/src/yuzu/mini_dump.cpp
new file mode 100644
index 0000000000..a34dc6a9c4
--- /dev/null
+++ b/src/yuzu/mini_dump.cpp
@@ -0,0 +1,202 @@
+// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+#include <filesystem>
+#include <fmt/format.h>
+#include <windows.h>
+#include "yuzu/mini_dump.h"
+#include "yuzu/startup_checks.h"
+
+// dbghelp.h must be included after windows.h
+#include <dbghelp.h>
+
+namespace MiniDump {
+
+void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info,
+                    EXCEPTION_POINTERS* pep) {
+    char file_name[255];
+    const std::time_t the_time = std::time(nullptr);
+    std::strftime(file_name, 255, "yuzu-crash-%Y%m%d%H%M%S.dmp", std::localtime(&the_time));
+
+    // Open the file
+    HANDLE file_handle = CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, 0, nullptr,
+                                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+
+    if (file_handle == nullptr || file_handle == INVALID_HANDLE_VALUE) {
+        fmt::print(stderr, "CreateFileA failed. Error: {}", GetLastError());
+        return;
+    }
+
+    // Create the minidump
+    const MINIDUMP_TYPE dump_type = MiniDumpNormal;
+
+    const bool write_dump_status = MiniDumpWriteDump(process_handle, process_id, file_handle,
+                                                     dump_type, (pep != 0) ? info : 0, 0, 0);
+
+    if (write_dump_status) {
+        fmt::print(stderr, "MiniDump created: {}", file_name);
+    } else {
+        fmt::print(stderr, "MiniDumpWriteDump failed. Error: {}", GetLastError());
+    }
+
+    // Close the file
+    CloseHandle(file_handle);
+}
+
+void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi) {
+    EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord;
+
+    HANDLE thread_handle = OpenThread(THREAD_GET_CONTEXT, false, deb_ev.dwThreadId);
+    if (thread_handle == nullptr) {
+        fmt::print(stderr, "OpenThread failed ({})", GetLastError());
+        return;
+    }
+
+    // Get child process context
+    CONTEXT context = {};
+    context.ContextFlags = CONTEXT_ALL;
+    if (!GetThreadContext(thread_handle, &context)) {
+        fmt::print(stderr, "GetThreadContext failed ({})", GetLastError());
+        return;
+    }
+
+    // Create exception pointers for minidump
+    EXCEPTION_POINTERS ep;
+    ep.ExceptionRecord = &record;
+    ep.ContextRecord = &context;
+
+    MINIDUMP_EXCEPTION_INFORMATION info;
+    info.ThreadId = deb_ev.dwThreadId;
+    info.ExceptionPointers = &ep;
+    info.ClientPointers = false;
+
+    CreateMiniDump(pi.hProcess, pi.dwProcessId, &info, &ep);
+
+    if (CloseHandle(thread_handle) == 0) {
+        fmt::print(stderr, "error: CloseHandle(thread_handle) failed ({})", GetLastError());
+    }
+}
+
+bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi) {
+    std::memset(&pi, 0, sizeof(pi));
+
+    // Don't debug if we are already being debugged
+    if (IsDebuggerPresent()) {
+        return false;
+    }
+
+    if (!SpawnChild(arg0, &pi, 0)) {
+        fmt::print(stderr, "warning: continuing without crash dumps");
+        return false;
+    }
+
+    const bool can_debug = DebugActiveProcess(pi.dwProcessId);
+    if (!can_debug) {
+        fmt::print(stderr,
+                   "warning: DebugActiveProcess failed ({}), continuing without crash dumps",
+                   GetLastError());
+        return false;
+    }
+
+    return true;
+}
+
+static const char* ExceptionName(DWORD exception) {
+    switch (exception) {
+    case EXCEPTION_ACCESS_VIOLATION:
+        return "EXCEPTION_ACCESS_VIOLATION";
+    case EXCEPTION_DATATYPE_MISALIGNMENT:
+        return "EXCEPTION_DATATYPE_MISALIGNMENT";
+    case EXCEPTION_BREAKPOINT:
+        return "EXCEPTION_BREAKPOINT";
+    case EXCEPTION_SINGLE_STEP:
+        return "EXCEPTION_SINGLE_STEP";
+    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+        return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
+    case EXCEPTION_FLT_DENORMAL_OPERAND:
+        return "EXCEPTION_FLT_DENORMAL_OPERAND";
+    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+        return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
+    case EXCEPTION_FLT_INEXACT_RESULT:
+        return "EXCEPTION_FLT_INEXACT_RESULT";
+    case EXCEPTION_FLT_INVALID_OPERATION:
+        return "EXCEPTION_FLT_INVALID_OPERATION";
+    case EXCEPTION_FLT_OVERFLOW:
+        return "EXCEPTION_FLT_OVERFLOW";
+    case EXCEPTION_FLT_STACK_CHECK:
+        return "EXCEPTION_FLT_STACK_CHECK";
+    case EXCEPTION_FLT_UNDERFLOW:
+        return "EXCEPTION_FLT_UNDERFLOW";
+    case EXCEPTION_INT_DIVIDE_BY_ZERO:
+        return "EXCEPTION_INT_DIVIDE_BY_ZERO";
+    case EXCEPTION_INT_OVERFLOW:
+        return "EXCEPTION_INT_OVERFLOW";
+    case EXCEPTION_PRIV_INSTRUCTION:
+        return "EXCEPTION_PRIV_INSTRUCTION";
+    case EXCEPTION_IN_PAGE_ERROR:
+        return "EXCEPTION_IN_PAGE_ERROR";
+    case EXCEPTION_ILLEGAL_INSTRUCTION:
+        return "EXCEPTION_ILLEGAL_INSTRUCTION";
+    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+        return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
+    case EXCEPTION_STACK_OVERFLOW:
+        return "EXCEPTION_STACK_OVERFLOW";
+    case EXCEPTION_INVALID_DISPOSITION:
+        return "EXCEPTION_INVALID_DISPOSITION";
+    case EXCEPTION_GUARD_PAGE:
+        return "EXCEPTION_GUARD_PAGE";
+    case EXCEPTION_INVALID_HANDLE:
+        return "EXCEPTION_INVALID_HANDLE";
+    default:
+        return "unknown exception type";
+    }
+}
+
+void DebugDebuggee(PROCESS_INFORMATION& pi) {
+    DEBUG_EVENT deb_ev = {};
+
+    while (deb_ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) {
+        const bool wait_success = WaitForDebugEvent(&deb_ev, INFINITE);
+        if (!wait_success) {
+            fmt::print(stderr, "error: WaitForDebugEvent failed ({})", GetLastError());
+            return;
+        }
+
+        switch (deb_ev.dwDebugEventCode) {
+        case OUTPUT_DEBUG_STRING_EVENT:
+        case CREATE_PROCESS_DEBUG_EVENT:
+        case CREATE_THREAD_DEBUG_EVENT:
+        case EXIT_PROCESS_DEBUG_EVENT:
+        case EXIT_THREAD_DEBUG_EVENT:
+        case LOAD_DLL_DEBUG_EVENT:
+        case RIP_EVENT:
+        case UNLOAD_DLL_DEBUG_EVENT:
+            // Continue on all other debug events
+            ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_CONTINUE);
+            break;
+        case EXCEPTION_DEBUG_EVENT:
+            EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord;
+
+            // We want to generate a crash dump if we are seeing the same exception again.
+            if (!deb_ev.u.Exception.dwFirstChance) {
+                fmt::print(stderr, "Creating MiniDump on ExceptionCode: 0x{:08x} {}\n",
+                           record.ExceptionCode, ExceptionName(record.ExceptionCode));
+                DumpFromDebugEvent(deb_ev, pi);
+            }
+
+            // Continue without handling the exception.
+            // Lets the debuggee use its own exception handler.
+            // - If one does not exist, we will see the exception once more where we make a minidump
+            //     for. Then when it reaches here again, yuzu will probably crash.
+            // - DBG_CONTINUE on an exception that the debuggee does not handle can set us up for an
+            //     infinite loop of exceptions.
+            ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
+            break;
+        }
+    }
+}
+
+} // namespace MiniDump
diff --git a/src/yuzu/mini_dump.h b/src/yuzu/mini_dump.h
new file mode 100644
index 0000000000..d6b6cca845
--- /dev/null
+++ b/src/yuzu/mini_dump.h
@@ -0,0 +1,19 @@
+// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <windows.h>
+
+#include <dbghelp.h>
+
+namespace MiniDump {
+
+void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info,
+                    EXCEPTION_POINTERS* pep);
+
+void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi);
+bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi);
+void DebugDebuggee(PROCESS_INFORMATION& pi);
+
+} // namespace MiniDump
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp
index 8421280bf2..29b87da051 100644
--- a/src/yuzu/startup_checks.cpp
+++ b/src/yuzu/startup_checks.cpp
@@ -31,19 +31,36 @@ void CheckVulkan() {
     }
 }
 
-bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
+bool CheckEnvVars(bool* is_child) {
 #ifdef _WIN32
     // Check environment variable to see if we are the child
     char variable_contents[8];
     const DWORD startup_check_var =
         GetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, variable_contents, 8);
-    if (startup_check_var > 0 && std::strncmp(variable_contents, "ON", 8) == 0) {
+    if (startup_check_var > 0 && std::strncmp(variable_contents, ENV_VAR_ENABLED_TEXT, 8) == 0) {
         CheckVulkan();
         return true;
     }
 
+    // Don't perform startup checks if we are a child process
+    char is_child_s[8];
+    const DWORD is_child_len = GetEnvironmentVariableA(IS_CHILD_ENV_VAR, is_child_s, 8);
+    if (is_child_len > 0 && std::strncmp(is_child_s, ENV_VAR_ENABLED_TEXT, 8) == 0) {
+        *is_child = true;
+        return false;
+    } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) {
+        std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n",
+                     IS_CHILD_ENV_VAR, GetLastError());
+        return true;
+    }
+#endif
+    return false;
+}
+
+bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
+#ifdef _WIN32
     // Set the startup variable for child processes
-    const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, "ON");
+    const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT);
     if (!env_var_set) {
         std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n",
                      STARTUP_CHECK_ENV_VAR, GetLastError());
@@ -53,7 +70,7 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
     PROCESS_INFORMATION process_info;
     std::memset(&process_info, '\0', sizeof(process_info));
 
-    if (!SpawnChild(arg0, &process_info)) {
+    if (!SpawnChild(arg0, &process_info, 0)) {
         return false;
     }
 
@@ -106,7 +123,7 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
 }
 
 #ifdef _WIN32
-bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi) {
+bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) {
     STARTUPINFOA startup_info;
 
     std::memset(&startup_info, '\0', sizeof(startup_info));
@@ -120,7 +137,7 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi) {
                                                 nullptr,       // lpProcessAttributes
                                                 nullptr,       // lpThreadAttributes
                                                 false,         // bInheritHandles
-                                                0,             // dwCreationFlags
+                                                flags,         // dwCreationFlags
                                                 nullptr,       // lpEnvironment
                                                 nullptr,       // lpCurrentDirectory
                                                 &startup_info, // lpStartupInfo
diff --git a/src/yuzu/startup_checks.h b/src/yuzu/startup_checks.h
index 096dd54a89..f2fc2d9d45 100644
--- a/src/yuzu/startup_checks.h
+++ b/src/yuzu/startup_checks.h
@@ -7,11 +7,14 @@
 #include <windows.h>
 #endif
 
+constexpr char IS_CHILD_ENV_VAR[] = "YUZU_IS_CHILD";
 constexpr char STARTUP_CHECK_ENV_VAR[] = "YUZU_DO_STARTUP_CHECKS";
+constexpr char ENV_VAR_ENABLED_TEXT[] = "ON";
 
 void CheckVulkan();
+bool CheckEnvVars(bool* is_child);
 bool StartupChecks(const char* arg0, bool* has_broken_vulkan);
 
 #ifdef _WIN32
-bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi);
+bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags);
 #endif
diff --git a/vcpkg.json b/vcpkg.json
index c4413e22ad..3c92510d60 100644
--- a/vcpkg.json
+++ b/vcpkg.json
@@ -31,6 +31,10 @@
         "yuzu-tests": {
             "description": "Compile tests",
             "dependencies": [ "catch2" ]
+        },
+        "dbghelp": {
+            "description": "Compile Windows crash dump (Minidump) support",
+            "dependencies": [ "dbghelp" ]
         }
     },
     "overrides": [