diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp
index fed9c2e5041030abb175513b4094902ea04c738a..1820543b05bfded3005727b903304ddd08613588 100644
--- a/indra/llfilesystem/lldir.cpp
+++ b/indra/llfilesystem/lldir.cpp
@@ -375,6 +375,12 @@ const std::string  LLDir::getCacheDir(bool get_default) const
 	}
 }
 
+const std::string  LLDir::getCacheDirPerGrid(bool get_default) const
+{
+	using namespace std::literals;
+	return add(getCacheDir(get_default), (mGrid.empty() ? "" : "gridcache"), mGrid);
+}
+
 // Return the default cache directory
 std::string LLDir::buildSLOSCacheDir() const
 {
@@ -473,6 +479,7 @@ static std::string ELLPathToString(ELLPath location)
 		ENT(LL_PATH_EXECUTABLE)
 		ENT(LL_PATH_DEFAULT_SKIN)
 		ENT(LL_PATH_FONTS)
+		ENT(LL_PATH_CACHE_PER_GRID)
 		ENT(LL_PATH_LAST)
 	;
 #undef ENT
@@ -518,6 +525,10 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
 		prefix = getCacheDir();
 		break;
 		
+	case LL_PATH_CACHE_PER_GRID:
+		prefix = getCacheDirPerGrid();
+		break;
+
     case LL_PATH_DUMP:
         prefix=getDumpDir();
         break;
@@ -957,12 +968,12 @@ void LLDir::setChatLogsDir(const std::string &path)
 
 void LLDir::updatePerAccountChatLogsDir()
 {
-	const std::string& logname = (mGrid.empty())
-		? mUserName : mUserName.append(".").append(mGrid);
+	const std::string logname = (mGrid.empty())
+		? mUserName : std::string(mUserName).append(".").append(mGrid);
 	mPerAccountChatLogsDir = add(getChatLogsDir(), logname);
 }
 
-void LLDir::setPerAccountChatLogsDir(const std::string &username, const std::string &gridname)
+void LLDir::setPerAccountChatLogsDir(const std::string &username)
 {
 	// if both first and last aren't set, assume we're grabbing the cached dir
 	if (!username.empty())
@@ -972,12 +983,8 @@ void LLDir::setPerAccountChatLogsDir(const std::string &username, const std::str
 		std::string userlower(username);
 		LLStringUtil::toLower(userlower);
 		LLStringUtil::replaceChar(userlower, ' ', '_');
-		std::string gridlower(gridname);
-		LLStringUtil::toLower(gridlower);
-		LLStringUtil::replaceChar(gridlower, ' ', '_');
 		
 		mUserName = userlower;
-		mGrid = gridlower;
 		updatePerAccountChatLogsDir();
 	}
 	else
@@ -1065,6 +1072,21 @@ bool LLDir::setCacheDir(const std::string &path)
 	}
 }
 
+void LLDir::setCurrentGrid(std::string gridname)
+{
+	if (gridname.empty())
+	{
+		mGrid.clear();
+	}
+	else
+	{
+		LLStringUtil::toLower(gridname);
+		LLStringUtil::replaceChar(gridname, ' ', '_');
+
+		mGrid = gridname;
+	}
+}
+
 void LLDir::dumpCurrentDirectories(LLError::ELevel level)
 {
 	LL_VLOGS(level, "AppInit","Directories") << "Current Directories:" << LL_ENDL;
diff --git a/indra/llfilesystem/lldir.h b/indra/llfilesystem/lldir.h
index 9035786e8157877e8ae9a89c5b78e930fdc7038d..c32086ca027786c2ed0dae3a29000358d6cc78ed 100644
--- a/indra/llfilesystem/lldir.h
+++ b/indra/llfilesystem/lldir.h
@@ -49,6 +49,7 @@ typedef enum ELLPath
 	LL_PATH_DEFAULT_SKIN = 17,
 	LL_PATH_FONTS = 18,
     LL_PATH_DUMP = 19,
+	LL_PATH_CACHE_PER_GRID = 20,
 	LL_PATH_LAST
 } ELLPath;
 
@@ -94,6 +95,7 @@ class LLDir
 	const std::string &getPerAccountChatLogsDir() const;	// Location of the per account chat logs dir.
 	const std::string &getTempDir() const;			// Common temporary directory
 	const std::string  getCacheDir(bool get_default = false) const;	// Location of the cache.
+	const std::string  getCacheDirPerGrid(bool get_default = false) const;	// Location of the per-grid cache.
 	const std::string &getOSCacheDir() const;		// location of OS-specific cache folder (may be empty string)
 	const std::string &getCAFile() const;			// File containing TLS certificate authorities
 	const std::string &getDirDelimiter() const;	// directory separator for platform (ie. '\' or '/' or ':')
@@ -184,7 +186,7 @@ class LLDir
 
 
 	virtual void setChatLogsDir(const std::string &path);		// Set the chat logs dir to this user's dir
-	virtual void setPerAccountChatLogsDir(const std::string &username, const std::string &gridname);		// Set the per user chat log directory.
+	virtual void setPerAccountChatLogsDir(const std::string &username);		// Set the per user chat log directory.
 	virtual void setLindenUserDir(const std::string &username, const std::string &gridname);		// Set the linden user dir to this user's dir
 	virtual void setSkinFolder(const std::string &skin_folder, const std::string& language);
 	virtual std::string getSkinFolder() const;
@@ -223,6 +225,8 @@ class LLDir
 		return destpath;
 	}
 
+	void setCurrentGrid(std::string grid);
+
 protected:
 	// Does an add() or append() call need a directory delimiter?
 	typedef std::pair<bool, unsigned short> SepOff;
diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp
index e9000dbdb40748ea3a8e4e689ec3969c92d24479..015e879d76529d0b7292d357268183c0483a117b 100644
--- a/indra/llmessage/llexperiencecache.cpp
+++ b/indra/llmessage/llexperiencecache.cpp
@@ -88,25 +88,9 @@ const int LLExperienceCache::SEARCH_PAGE_SIZE     = 30;
 bool LLExperienceCache::sShutdown = false;
 
 //=========================================================================
-LLExperienceCache::LLExperienceCache(std::string grid)
-{
-    std::string file;
-    if (grid.empty())
-    {
-        file = "experience_cache.xml";
-    }
-    else
-    {
-        LLStringUtil::toLower(grid);
-        LLStringUtil::replaceChar(grid, ' ', '_');
-        file = llformat("experience_cache.%s.xml", grid);
-    }
-
-    mCacheFileName = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, file);
-}
-
 void LLExperienceCache::initSingleton()
 {
+    mCacheFileName = gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, "experience_cache.xml");
     LL_INFOS("ExperienceCache") << "Loading " << mCacheFileName << LL_ENDL;
     llifstream cache_stream(mCacheFileName.c_str());
 
diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h
index 8f38ac316c65746f33cdd95ddccb2bb40673f11f..b1fe4348a7e11b9e591634d56a8f3316c2e755bc 100644
--- a/indra/llmessage/llexperiencecache.h
+++ b/indra/llmessage/llexperiencecache.h
@@ -41,9 +41,9 @@ class LLSD;
 class LLUUID;
 
 
-class LLExperienceCache final : public LLParamSingleton < LLExperienceCache >
+class LLExperienceCache final : public LLSingleton < LLExperienceCache >
 {
-    LLSINGLETON(LLExperienceCache, std::string);
+    LLSINGLETON_EMPTY_CTOR(LLExperienceCache);
 
 public:
     typedef boost::function<std::string(const std::string &)> CapabilityQuery_t;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 3a29a07a97f03eef6f472fc754b2b2ef5a50f3e8..35ace70b7a2923554465c6ffbb71432092b53113 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4275,8 +4275,6 @@ bool LLAppViewer::initCache()
 
 	LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);
 
-	LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion());
-
     return true;
 }
 
@@ -4418,6 +4416,7 @@ void LLAppViewer::purgeCache()
 	LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL;
 	LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE);
 	LLVOCache::getInstance()->removeCache(LL_PATH_CACHE);
+	LLVOCache::getInstance()->removeCache(LL_PATH_CACHE_PER_GRID);
 	std::string browser_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache");
 	if (LLFile::isdir(browser_cache))
 	{
@@ -4437,7 +4436,7 @@ void LLAppViewer::purgeCacheImmediate()
 {
 	LL_INFOS("AppCache") << "Purging Object Cache and Texture Cache immediately..." << LL_ENDL;
 	LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE, false);
-	LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true);
+	LLVOCache::getInstance()->removeCache(LL_PATH_CACHE_PER_GRID, true);
 }
 
 std::string LLAppViewer::getSecondLifeTitle() const
@@ -4580,19 +4579,8 @@ void LLAppViewer::saveFinalSnapshot()
 void LLAppViewer::loadNameCache()
 {
 	// display names cache
-	std::string file;
-	if (LLGridManager::getInstance()->isInSecondlife())
-	{
-		file = "avatar_name_cache.xml";
-	}
-	else
-	{
-		std::string gridlabel = LLGridManager::getInstance()->getGridId();
-		LLStringUtil::toLower(gridlabel);
-		file = llformat("avatar_name_cache.%s.xml", gridlabel.c_str());
-	}
 	std::string filename =
-		gDirUtilp->getExpandedFilename(LL_PATH_CACHE, file);
+		gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, "avatar_name_cache.xml");
 	LL_INFOS("AvNameCache") << filename << LL_ENDL;
 	llifstream name_cache_stream(filename.c_str());
 	if(name_cache_stream.is_open())
@@ -4607,19 +4595,7 @@ void LLAppViewer::loadNameCache()
 
 	if (!gCacheName) return;
 
-	std::string name_file;
-	if (LLGridManager::getInstance()->isInSecondlife())
-	{
-		name_file = "name.cache";
-	}
-	else
-	{
-		std::string gridid = LLGridManager::getInstance()->getGridId();
-		LLStringUtil::toLower(gridid);
-		name_file = llformat("name.%s.cache", gridid.c_str());
-	}
-
-	std::string name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, name_file);
+	std::string name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, "name.cache");
 	llifstream cache_file(name_cache.c_str());
 	if(cache_file.is_open())
 	{
@@ -4630,19 +4606,8 @@ void LLAppViewer::loadNameCache()
 void LLAppViewer::saveNameCache()
 {
 	// display names cache
-	std::string file;
-	if (LLGridManager::getInstance()->isInSecondlife())
-	{
-		file = "avatar_name_cache.xml";
-	}
-	else
-	{
-		std::string gridlabel = LLGridManager::getInstance()->getGridId();
-		LLStringUtil::toLower(gridlabel);
-		file = llformat("avatar_name_cache.%s.xml", gridlabel.c_str());
-	}
 	std::string filename =
-		gDirUtilp->getExpandedFilename(LL_PATH_CACHE, file);
+		gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, "avatar_name_cache.xml");
 	llofstream name_cache_stream(filename.c_str());
 	if(name_cache_stream.is_open())
 	{
@@ -4652,19 +4617,7 @@ void LLAppViewer::saveNameCache()
     // real names cache
 	if (gCacheName)
     {
-		std::string name_file;
-		if (LLGridManager::getInstance()->isInSecondlife())
-		{
-			name_file = "name.cache";
-		}
-		else
-		{
-			std::string gridid = LLGridManager::getInstance()->getGridId();
-			LLStringUtil::toLower(gridid);
-			name_file = llformat("name.%s.cache", gridid.c_str());
-		}
-
-        std::string name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, name_file);
+        std::string name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, "name.cache");
         llofstream cache_file(name_cache.c_str());
         if(cache_file.is_open())
         {
diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp
index 46aa6958ff8c9e46f4aa8d3e1a18fd7f12d9b5cd..ca98600a84ac63a69cace76265507bdcdd249c75 100644
--- a/indra/newview/llavatariconctrl.cpp
+++ b/indra/newview/llavatariconctrl.cpp
@@ -75,7 +75,7 @@ void LLAvatarIconIDCache::load	()
 	LL_INFOS() << "Loading avatar icon id cache." << LL_ENDL;
 	
 	// build filename for each user
-	std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, mFilename);
+	std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, mFilename);
 	llifstream file(resolved_filename.c_str());
 
 	if (!file.is_open())
@@ -111,7 +111,7 @@ void LLAvatarIconIDCache::load	()
 
 void LLAvatarIconIDCache::save	()
 {
-	std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, mFilename);
+	std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, mFilename);
 
 	// open a file for writing
 	llofstream file (resolved_filename.c_str());
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index e6a77c8ccbb1e1336b64b7b0e4487ef4c6d7392e..dc657821c9a4dce0555eb86253d21744ffc00f65 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -81,8 +81,6 @@ BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE;
 ///----------------------------------------------------------------------------
 
 //BOOL decompress_file(const char* src_filename, const char* dst_filename);
-static const char PRODUCTION_CACHE_FORMAT_STRING[] = "%s.inv.llsd";
-static const char GRID_CACHE_FORMAT_STRING[] = "%s.%s.inv.llsd";
 static const char * const LOG_INV("Inventory");
 
 struct InventoryIDPtrLess
@@ -1896,24 +1894,7 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const
 //static
 std::string LLInventoryModel::getInvCacheAddres(const LLUUID& owner_id)
 {
-    std::string inventory_addr;
-    std::string owner_id_str;
-    owner_id.toString(owner_id_str);
-    std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str));
-    if (LLGridManager::getInstance()->isInSLMain())
-    {
-        inventory_addr = llformat(PRODUCTION_CACHE_FORMAT_STRING, path.c_str());
-    }
-    else
-    {
-        // NOTE: The inventory cache filenames now include the grid name.
-        // Add controls against directory traversal or problematic pathname lengths
-        // if your viewer uses grid names from an untrusted source.
-        const std::string& grid_id_str = LLGridManager::getInstance()->getGridId();
-        const std::string& grid_id_lower = utf8str_tolower(grid_id_str);
-        inventory_addr = llformat(GRID_CACHE_FORMAT_STRING, path.c_str(), grid_id_lower.c_str());
-    }
-    return inventory_addr;
+	return gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, owner_id.asString(), ".inv.llsd");
 }
 
 void LLInventoryModel::cache(
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index dbf4a3e5130e74abd482b5573b5d895decc5bc2d..625f04589f814f2508a13947c1abf18f9a79e2b4 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -743,12 +743,16 @@ BOOL LLMuteList::isMuted(const std::string& username, U32 flags) const
 //-----------------------------------------------------------------------------
 // requestFromServer()
 //-----------------------------------------------------------------------------
+
+std::string get_mutes_cache_file(const LLUUID& agent_id)
+{
+	return gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, agent_id.asString()).append(".cached_mute");
+
+}
+
 void LLMuteList::requestFromServer(const LLUUID& agent_id)
 {
-	std::string agent_id_string;
-	std::string filename;
-	agent_id.toString(agent_id_string);
-	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute";
+	std::string filename = get_mutes_cache_file(agent_id);
 	LLCRC crc;
 	crc.update(filename);
 
@@ -784,10 +788,7 @@ void LLMuteList::cache(const LLUUID& agent_id)
 	// Write to disk even if empty.
 	if(mIsLoaded)
 	{
-		std::string agent_id_string;
-		std::string filename;
-		agent_id.toString(agent_id_string);
-		filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute";
+		std::string filename = get_mutes_cache_file(agent_id);
 		saveToFile(filename);
 	}
 }
@@ -825,10 +826,7 @@ void LLMuteList::processUseCachedMuteList(LLMessageSystem* msg, void**)
 {
 	LL_INFOS() << "LLMuteList::processUseCachedMuteList()" << LL_ENDL;
 
-	std::string agent_id_string;
-	gAgent.getID().toString(agent_id_string);
-	std::string filename;
-	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute";
+	std::string filename = get_mutes_cache_file(gAgent.getID());
 	LLMuteList::getInstance()->loadFromFile(filename);
 }
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index ed87dceece81011734314889cb0c4fb3fa4586da..b484d9acf5556cb3d2030fab907204be136a664c 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -175,6 +175,7 @@
 #include "llviewerwindow.h"
 #include "llvoavatar.h"
 #include "llvoavatarself.h"
+#include "llvocache.h"
 #include "llweb.h"
 #include "llworld.h"
 #include "llworldmapmessage.h"
@@ -948,6 +949,12 @@ bool idle_startup()
 		// create necessary directories
 		// *FIX: these mkdir's should error check
 		const std::string& gridlabel = !LLGridManager::getInstance()->isInSecondlife() ? LLGridManager::getInstance()->getGridId() : LLStringUtil::null;
+		gDirUtilp->setCurrentGrid(gridlabel);
+		LLFile::mkdir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "gridcache", ""));
+		LLFile::mkdir(gDirUtilp->getCacheDirPerGrid());
+
+		LLVOCache::getInstance()->initCache(LL_PATH_CACHE_PER_GRID, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), LLAppViewer::getObjectCacheVersion());
+
 		gDirUtilp->setLindenUserDir(userid, gridlabel);
 		LLFile::mkdir(gDirUtilp->getLindenUserDir());
 
@@ -996,7 +1003,7 @@ bool idle_startup()
 		{
 			gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));		
 		}
-		gDirUtilp->setPerAccountChatLogsDir(userid, gridlabel);
+		gDirUtilp->setPerAccountChatLogsDir(userid);
 		
 		LLFile::mkdir(gDirUtilp->getChatLogsDir());
 		LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir());
@@ -2147,7 +2154,9 @@ bool idle_startup()
 			gAgentWearables.notifyLoadingStarted();
 			gAgent.setOutfitChosen(TRUE);
 			if (LLGridManager::getInstance()->isInSecondlife())
+			{
 				gAgentWearables.sendDummyAgentWearablesUpdate();
+			}
 			callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(), set_flags_and_update_appearance);
 		}
 
@@ -2235,6 +2244,9 @@ bool idle_startup()
 				LLStartUp::setStartupState( STATE_CLEANUP );
 				return TRUE;
 			}
+
+			// Can't fall through here, so return
+			return TRUE;
 		}
 		//fall through this frame to STATE_CLEANUP
 	}
@@ -2935,8 +2947,6 @@ void LLStartUp::initNameCache()
 void LLStartUp::initExperiences()
 {   
     // Should trigger loading the cache.
-	const std::string& gridlabel = !LLGridManager::getInstance()->isInSecondlife() ? LLGridManager::getInstance()->getGridId() : LLStringUtil::null;
-	LLExperienceCache::initParamSingleton(gridlabel);
     LLExperienceCache::instance().setCapabilityQuery(
         boost::bind(&LLAgent::getRegionCapability, &gAgent, _1));
 
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 34972894831e8f37fcc7fe523840ca573290be1b..76cd67c9f25f26c85e4c57e9d12819e6bce6362b 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -201,7 +201,7 @@ void LLViewerTextureList::doPreloadImages()
 
 static std::string get_texture_list_name()
 {
-	return gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "texture_list_" + gSavedSettings.getString("LoginLocation") + "." + gDirUtilp->getUserName() + ".xml");
+	return gDirUtilp->getExpandedFilename(LL_PATH_CACHE_PER_GRID, "texture_list_" + gSavedSettings.getString("LoginLocation") + "." + gDirUtilp->getUserName() + ".xml");
 }
 
 void LLViewerTextureList::doPrefetchImages()
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 628fdb55ec4159362614a9a381a18aa5f6d190d3..c35467a5a0af403fcf082af88d688a94e8cc6633 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -35,6 +35,7 @@
 #include "pipeline.h"
 #include "llagentcamera.h"
 #include "llmemory.h"
+#include "llviewernetwork.h"
 
 //static variables
 U32 LLVOCacheEntry::sMinFrameRange = 0;
@@ -1196,12 +1197,9 @@ void LLVOCache::clearCacheInMemory()
 void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename) 
 {
 	U32 region_x, region_y;
-
 	grid_from_region_handle(handle, &region_x, &region_y);
-	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, object_cache_dirname,
-			   llformat(OBJECT_CACHE_FILENAME, region_x, region_y));
 
-	return ;
+	filename = gDirUtilp->add(mObjectCacheDirName, llformat(OBJECT_CACHE_FILENAME, region_x, region_y));
 }
 
 void LLVOCache::removeFromCache(HeaderEntryInfo* entry)