diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9d22cc9458..46e2dc8399 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -598,6 +598,8 @@ add_library(core STATIC
     hle/service/mii/mii.h
     hle/service/mii/mii_database.cpp
     hle/service/mii/mii_database.h
+    hle/service/mii/mii_database_manager.cpp
+    hle/service/mii/mii_database_manager.h
     hle/service/mii/mii_manager.cpp
     hle/service/mii/mii_manager.h
     hle/service/mii/mii_result.h
diff --git a/src/core/hle/service/mii/mii_database_manager.cpp b/src/core/hle/service/mii/mii_database_manager.cpp
new file mode 100644
index 0000000000..63c411690c
--- /dev/null
+++ b/src/core/hle/service/mii/mii_database_manager.cpp
@@ -0,0 +1,420 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/assert.h"
+#include "common/fs/file.h"
+#include "common/fs/fs.h"
+#include "common/fs/path_util.h"
+#include "common/logging/log.h"
+#include "common/string_util.h"
+
+#include "core/hle/service/mii/mii_database_manager.h"
+#include "core/hle/service/mii/mii_result.h"
+#include "core/hle/service/mii/mii_util.h"
+#include "core/hle/service/mii/types/char_info.h"
+#include "core/hle/service/mii/types/store_data.h"
+
+namespace Service::Mii {
+constexpr std::string DbFileName = "MiiDatabase.dat";
+
+DatabaseManager::DatabaseManager() {}
+
+Result DatabaseManager::MountSaveData() {
+    if (!is_save_data_mounted) {
+        system_save_dir =
+            Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000030";
+        if (is_test_db) {
+            system_save_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) /
+                              "system/save/8000000000000031";
+        }
+
+        // mount point should be "mii:"
+
+        if (!Common::FS::CreateDirs(system_save_dir)) {
+            return ResultUnknown;
+        }
+    }
+
+    is_save_data_mounted = true;
+    return ResultSuccess;
+}
+
+Result DatabaseManager::Initialize(DatabaseSessionMetadata& metadata, bool& is_database_broken) {
+    is_database_broken = false;
+    if (!is_save_data_mounted) {
+        return ResultInvalidArgument;
+    }
+
+    database.CleanDatabase();
+    update_counter++;
+    metadata.update_counter = update_counter;
+
+    const Common::FS::IOFile db_file{system_save_dir / DbFileName, Common::FS::FileAccessMode::Read,
+                                     Common::FS::FileType::BinaryFile};
+
+    if (!db_file.IsOpen()) {
+        return SaveDatabase();
+    }
+
+    if (Common::FS::GetSize(system_save_dir / DbFileName) != sizeof(NintendoFigurineDatabase)) {
+        is_database_broken = true;
+    }
+
+    if (db_file.Read(database) != 1) {
+        is_database_broken = true;
+    }
+
+    if (is_database_broken) {
+        // Dragons happen here for simplicity just clean the database
+        LOG_ERROR(Service_Mii, "Mii database is corrupted");
+        database.CleanDatabase();
+        return ResultUnknown;
+    }
+
+    const auto result = database.CheckIntegrity();
+
+    if (result.IsError()) {
+        LOG_ERROR(Service_Mii, "Mii database is corrupted 0x{:0x}", result.raw);
+        database.CleanDatabase();
+        return ResultSuccess;
+    }
+
+    LOG_INFO(Service_Mii, "Successfully loaded mii database. size={}",
+             database.GetDatabaseLength());
+    return ResultSuccess;
+}
+
+bool DatabaseManager::IsFullDatabase() const {
+    return database.GetDatabaseLength() == MaxDatabaseLength;
+}
+
+bool DatabaseManager::IsModified() const {
+    return is_moddified;
+}
+
+u64 DatabaseManager::GetUpdateCounter() const {
+    return update_counter;
+}
+
+u32 DatabaseManager::GetCount(const DatabaseSessionMetadata& metadata) const {
+    const u32 database_size = database.GetDatabaseLength();
+    if (metadata.magic == MiiMagic) {
+        return database_size;
+    }
+
+    // Special mii can't be used. Skip those.
+
+    u32 mii_count{};
+    for (std::size_t index = 0; index < database_size; ++index) {
+        const auto& store_data = database.Get(index);
+        if (store_data.IsSpecial()) {
+            continue;
+        }
+        mii_count++;
+    }
+
+    return mii_count;
+}
+
+void DatabaseManager::Get(StoreData& out_store_data, std::size_t index,
+                          const DatabaseSessionMetadata& metadata) const {
+    if (metadata.magic == MiiMagic) {
+        out_store_data = database.Get(index);
+        return;
+    }
+
+    // The index refeers to the mii index without special mii.
+    // Search on the database until we find it
+
+    u32 virtual_index = 0;
+    const u32 database_size = database.GetDatabaseLength();
+    for (std::size_t i = 0; i < database_size; ++i) {
+        const auto& store_data = database.Get(i);
+        if (store_data.IsSpecial()) {
+            continue;
+        }
+        if (virtual_index == index) {
+            out_store_data = store_data;
+            return;
+        }
+        virtual_index++;
+    }
+
+    // This function doesn't fail. It returns the first mii instead
+    out_store_data = database.Get(0);
+}
+
+Result DatabaseManager::FindIndex(s32& out_index, const Common::UUID& create_id,
+                                  bool is_special) const {
+    u32 index{};
+    const bool is_found = database.GetIndexByCreatorId(index, create_id);
+
+    if (!is_found) {
+        return ResultNotFound;
+    }
+
+    if (is_special) {
+        out_index = index;
+        return ResultSuccess;
+    }
+
+    if (database.Get(index).IsSpecial()) {
+        return ResultNotFound;
+    }
+
+    out_index = 0;
+
+    if (index < 1) {
+        return ResultSuccess;
+    }
+
+    for (std::size_t i = 0; i <= index; ++i) {
+        if (database.Get(i).IsSpecial()) {
+            continue;
+        }
+        out_index++;
+    }
+    return ResultSuccess;
+}
+
+Result DatabaseManager::FindIndex(const DatabaseSessionMetadata& metadata, u32& out_index,
+                                  const Common::UUID& create_id) const {
+    u32 index{};
+    const bool is_found = database.GetIndexByCreatorId(index, create_id);
+
+    if (!is_found) {
+        return ResultNotFound;
+    }
+
+    if (metadata.magic == MiiMagic) {
+        out_index = index;
+        return ResultSuccess;
+    }
+
+    if (database.Get(index).IsSpecial()) {
+        return ResultNotFound;
+    }
+
+    out_index = 0;
+
+    if (index < 1) {
+        return ResultSuccess;
+    }
+
+    // The index refeers to the mii index without special mii.
+    // Search on the database until we find it
+
+    for (std::size_t i = 0; i <= index; ++i) {
+        const auto& store_data = database.Get(i);
+        if (store_data.IsSpecial()) {
+            continue;
+        }
+        out_index++;
+    }
+    return ResultSuccess;
+}
+
+Result DatabaseManager::FindMoveIndex(u32& out_index, u32 new_index,
+                                      const Common::UUID& create_id) const {
+    const auto database_size = database.GetDatabaseLength();
+
+    if (database_size >= 1) {
+        u32 virtual_index{};
+        for (std::size_t i = 0; i < database_size; ++i) {
+            const StoreData& store_data = database.Get(i);
+            if (store_data.IsSpecial()) {
+                continue;
+            }
+            if (virtual_index == new_index) {
+                const bool is_found = database.GetIndexByCreatorId(out_index, create_id);
+                if (!is_found) {
+                    return ResultNotFound;
+                }
+                if (store_data.IsSpecial()) {
+                    return ResultInvalidOperation;
+                }
+                return ResultSuccess;
+            }
+            virtual_index++;
+        }
+    }
+
+    const bool is_found = database.GetIndexByCreatorId(out_index, create_id);
+    if (!is_found) {
+        return ResultNotFound;
+    }
+    const StoreData& store_data = database.Get(out_index);
+    if (store_data.IsSpecial()) {
+        return ResultInvalidOperation;
+    }
+    return ResultSuccess;
+}
+
+Result DatabaseManager::Move(DatabaseSessionMetadata& metadata, u32 new_index,
+                             const Common::UUID& create_id) {
+    u32 current_index{};
+    if (metadata.magic == MiiMagic) {
+        const bool is_found = database.GetIndexByCreatorId(current_index, create_id);
+        if (!is_found) {
+            return ResultNotFound;
+        }
+    } else {
+        const auto result = FindMoveIndex(current_index, new_index, create_id);
+        if (result.IsError()) {
+            return result;
+        }
+    }
+
+    const auto result = database.Move(current_index, new_index);
+    if (result.IsFailure()) {
+        return result;
+    }
+
+    is_moddified = true;
+    update_counter++;
+    metadata.update_counter = update_counter;
+    return ResultSuccess;
+}
+
+Result DatabaseManager::AddOrReplace(DatabaseSessionMetadata& metadata,
+                                     const StoreData& store_data) {
+    if (store_data.IsValid() != ValidationResult::NoErrors) {
+        return ResultInvalidStoreData;
+    }
+    if (metadata.magic != MiiMagic && store_data.IsSpecial()) {
+        return ResultInvalidOperation;
+    }
+
+    u32 index{};
+    const bool is_found = database.GetIndexByCreatorId(index, store_data.GetCreateId());
+    if (is_found) {
+        const StoreData& old_store_data = database.Get(index);
+
+        if (store_data.IsSpecial() != old_store_data.IsSpecial()) {
+            return ResultInvalidOperation;
+        }
+
+        database.Replace(index, store_data);
+    } else {
+        if (database.IsFull()) {
+            return ResultDatabaseFull;
+        }
+
+        database.Add(store_data);
+    }
+
+    is_moddified = true;
+    update_counter++;
+    metadata.update_counter = update_counter;
+    return ResultSuccess;
+}
+
+Result DatabaseManager::Delete(DatabaseSessionMetadata& metadata, const Common::UUID& create_id) {
+    u32 index{};
+    const bool is_found = database.GetIndexByCreatorId(index, create_id);
+    if (!is_found) {
+        return ResultNotFound;
+    }
+
+    if (metadata.magic != MiiMagic) {
+        const auto& store_data = database.Get(index);
+        if (store_data.IsSpecial()) {
+            return ResultInvalidOperation;
+        }
+    }
+
+    database.Delete(index);
+
+    is_moddified = true;
+    update_counter++;
+    metadata.update_counter = update_counter;
+    return ResultSuccess;
+}
+
+Result DatabaseManager::Append(DatabaseSessionMetadata& metadata, const CharInfo& char_info) {
+    if (char_info.Verify() != ValidationResult::NoErrors) {
+        return ResultInvalidCharInfo2;
+    }
+    if (char_info.GetType() == 1) {
+        return ResultInvalidCharInfoType;
+    }
+
+    u32 index{};
+    StoreData store_data{};
+
+    // Loop until the mii we created is not on the database
+    do {
+        store_data.BuildWithCharInfo(char_info);
+    } while (database.GetIndexByCreatorId(index, store_data.GetCreateId()));
+
+    const Result result = store_data.Restore();
+
+    if (result.IsSuccess() || result == ResultNotUpdated) {
+        return AddOrReplace(metadata, store_data);
+    }
+
+    return result;
+}
+
+Result DatabaseManager::DestroyFile(DatabaseSessionMetadata& metadata) {
+    database.CorruptCrc();
+
+    is_moddified = true;
+    update_counter++;
+    metadata.update_counter = update_counter;
+
+    const auto result = SaveDatabase();
+    database.CleanDatabase();
+
+    return result;
+}
+
+Result DatabaseManager::DeleteFile() {
+    const bool result = Common::FS::RemoveFile(system_save_dir / DbFileName);
+    // Return proper FS error here
+    return result ? ResultSuccess : ResultUnknown;
+}
+
+void DatabaseManager::Format(DatabaseSessionMetadata& metadata) {
+    database.CleanDatabase();
+    is_moddified = true;
+    update_counter++;
+    metadata.update_counter = update_counter;
+}
+
+Result DatabaseManager::SaveDatabase() {
+    // TODO: Replace unknown error codes with proper FS error codes when available
+
+    if (!Common::FS::Exists(system_save_dir / DbFileName)) {
+        if (!Common::FS::NewFile(system_save_dir / DbFileName)) {
+            LOG_ERROR(Service_Mii, "Failed to create mii database");
+            return ResultUnknown;
+        }
+    }
+
+    const auto file_size = Common::FS::GetSize(system_save_dir / DbFileName);
+    if (file_size != 0 && file_size != sizeof(NintendoFigurineDatabase)) {
+        if (!Common::FS::RemoveFile(system_save_dir / DbFileName)) {
+            LOG_ERROR(Service_Mii, "Failed to delete mii database");
+            return ResultUnknown;
+        }
+        if (!Common::FS::NewFile(system_save_dir / DbFileName)) {
+            LOG_ERROR(Service_Mii, "Failed to create mii database");
+            return ResultUnknown;
+        }
+    }
+
+    const Common::FS::IOFile db_file{system_save_dir / DbFileName,
+                                     Common::FS::FileAccessMode::ReadWrite,
+                                     Common::FS::FileType::BinaryFile};
+
+    if (db_file.Write(database) != 1) {
+        LOG_ERROR(Service_Mii, "Failed to save mii database");
+        return ResultUnknown;
+    }
+
+    is_moddified = false;
+    return ResultSuccess;
+}
+
+} // namespace Service::Mii
diff --git a/src/core/hle/service/mii/mii_database_manager.h b/src/core/hle/service/mii/mii_database_manager.h
new file mode 100644
index 0000000000..52c32be82c
--- /dev/null
+++ b/src/core/hle/service/mii/mii_database_manager.h
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/fs/fs.h"
+#include "core/hle/result.h"
+#include "core/hle/service/mii/mii_database.h"
+
+namespace Service::Mii {
+class CharInfo;
+class StoreData;
+
+class DatabaseManager {
+public:
+    DatabaseManager();
+    Result MountSaveData();
+    Result Initialize(DatabaseSessionMetadata& metadata, bool& is_database_broken);
+
+    bool IsFullDatabase() const;
+    bool IsModified() const;
+    u64 GetUpdateCounter() const;
+
+    void Get(StoreData& out_store_data, std::size_t index,
+             const DatabaseSessionMetadata& metadata) const;
+    u32 GetCount(const DatabaseSessionMetadata& metadata) const;
+
+    Result FindIndex(s32& out_index, const Common::UUID& create_id, bool is_special) const;
+    Result FindIndex(const DatabaseSessionMetadata& metadata, u32& out_index,
+                     const Common::UUID& create_id) const;
+    Result FindMoveIndex(u32& out_index, u32 new_index, const Common::UUID& create_id) const;
+
+    Result Move(DatabaseSessionMetadata& metadata, u32 current_index,
+                const Common::UUID& create_id);
+    Result AddOrReplace(DatabaseSessionMetadata& metadata, const StoreData& out_store_data);
+    Result Delete(DatabaseSessionMetadata& metadata, const Common::UUID& create_id);
+    Result Append(DatabaseSessionMetadata& metadata, const CharInfo& char_info);
+
+    Result DestroyFile(DatabaseSessionMetadata& metadata);
+    Result DeleteFile();
+    void Format(DatabaseSessionMetadata& metadata);
+
+    Result SaveDatabase();
+
+private:
+    // This is the global value of
+    // nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled");
+    bool is_test_db{};
+
+    bool is_moddified{};
+    bool is_save_data_mounted{};
+    u64 update_counter{};
+    NintendoFigurineDatabase database{};
+
+    std::filesystem::path system_save_dir{};
+};
+
+}; // namespace Service::Mii