diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp
index 658c6a62f3..6d87bab40e 100644
--- a/Source/Core/Core/ConfigManager.cpp
+++ b/Source/Core/Core/ConfigManager.cpp
@@ -766,8 +766,7 @@ void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd)
   }
 
   // If not launching a disc game, just read everything from the TMD.
-  SetRunningGameMetadata(StringFromFormat("%016" PRIX64, tmd_title_id), tmd_title_id,
-                         tmd.GetTitleVersion());
+  SetRunningGameMetadata(tmd.GetGameID(), tmd_title_id, tmd.GetTitleVersion());
 }
 
 void SConfig::SetRunningGameMetadata(const std::string& game_id, u64 title_id, u16 revision)
diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp
index 60900dec60..4d4c8069eb 100644
--- a/Source/Core/Core/IOS/ES/Formats.cpp
+++ b/Source/Core/Core/IOS/ES/Formats.cpp
@@ -5,14 +5,18 @@
 #include "Core/IOS/ES/Formats.h"
 
 #include <algorithm>
+#include <cinttypes>
 #include <cstddef>
 #include <cstring>
+#include <locale>
+#include <string>
 #include <utility>
 #include <vector>
 
 #include "Common/ChunkFile.h"
 #include "Common/CommonTypes.h"
 #include "Common/Crypto/AES.h"
+#include "Common/StringUtil.h"
 #include "Common/Swap.h"
 #include "Core/ec_wii.h"
 
@@ -145,6 +149,22 @@ u16 TMDReader::GetGroupId() const
   return Common::swap16(m_bytes.data() + offsetof(TMDHeader, group_id));
 }
 
+std::string TMDReader::GetGameID() const
+{
+  char game_id[6];
+  std::memcpy(game_id, m_bytes.data() + offsetof(TMDHeader, title_id) + 4, 4);
+  std::memcpy(game_id + 4, m_bytes.data() + offsetof(TMDHeader, group_id), 2);
+
+  const bool all_printable = std::all_of(std::begin(game_id), std::end(game_id), [](char c) {
+    return std::isprint(c, std::locale::classic());
+  });
+
+  if (all_printable)
+    return std::string(game_id, sizeof(game_id));
+
+  return StringFromFormat("%016" PRIx64, GetTitleId());
+}
+
 u16 TMDReader::GetNumContents() const
 {
   return Common::swap16(m_bytes.data() + offsetof(TMDHeader, num_contents));
diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h
index d5543599c1..740c2f7646 100644
--- a/Source/Core/Core/IOS/ES/Formats.h
+++ b/Source/Core/Core/IOS/ES/Formats.h
@@ -8,6 +8,7 @@
 #pragma once
 
 #include <array>
+#include <string>
 #include <vector>
 
 #include "Common/ChunkFile.h"
@@ -143,6 +144,11 @@ public:
   u16 GetTitleVersion() const;
   u16 GetGroupId() const;
 
+  // Constructs a 6-character game ID in the format typically used by Dolphin.
+  // If the 6-character game ID would contain unprintable characters,
+  // the title ID converted to hexadecimal is returned instead.
+  std::string GetGameID() const;
+
   u16 GetNumContents() const;
   bool GetContent(u16 index, Content* content) const;
   std::vector<Content> GetContents() const;
diff --git a/Source/Core/DiscIO/VolumeWad.cpp b/Source/Core/DiscIO/VolumeWad.cpp
index a06c7483e8..13bc0f26c4 100644
--- a/Source/Core/DiscIO/VolumeWad.cpp
+++ b/Source/Core/DiscIO/VolumeWad.cpp
@@ -4,6 +4,7 @@
 
 #include <cstddef>
 #include <cstring>
+#include <locale>
 #include <map>
 #include <memory>
 #include <string>
@@ -89,22 +90,18 @@ IOS::ES::TMDReader CVolumeWAD::GetTMD() const
 
 std::string CVolumeWAD::GetGameID() const
 {
-  char GameCode[6];
-  if (!Read(m_offset + 0x01E0, 4, (u8*)GameCode))
-    return "0";
-
-  std::string temp = GetMakerID();
-  GameCode[4] = temp.at(0);
-  GameCode[5] = temp.at(1);
-
-  return DecodeString(GameCode);
+  return m_tmd.GetGameID();
 }
 
 std::string CVolumeWAD::GetMakerID() const
 {
-  char temp[2] = {1};
-  // Some weird channels use 0x0000 in place of the MakerID, so we need a check there
-  if (!Read(0x198 + m_tmd_offset, 2, (u8*)temp) || temp[0] == 0 || temp[1] == 0)
+  char temp[2];
+  if (!Read(0x198 + m_tmd_offset, 2, (u8*)temp))
+    return "00";
+
+  // Some weird channels use 0x0000 in place of the MakerID, so we need a check here
+  const std::locale& c_locale = std::locale::classic();
+  if (!std::isprint(temp[0], c_locale) || !std::isprint(temp[1], c_locale))
     return "00";
 
   return DecodeString(temp);