diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 7c9a54d31..e609dc32b 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -8475,6 +8475,11 @@ void Context::onGPUSwitch()
     initRendererString();
 }
 
+std::mutex &Context::getProgramCacheMutex() const
+{
+    return mDisplay->getProgramCacheMutex();
+}
+
 // ErrorSet implementation.
 ErrorSet::ErrorSet(Context *context) : mContext(context) {}
 
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index b80097fee..ee3f77cf2 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -10,6 +10,7 @@
 #ifndef LIBANGLE_CONTEXT_H_
 #define LIBANGLE_CONTEXT_H_
 
+#include <mutex>
 #include <set>
 #include <string>
 
@@ -506,6 +507,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
     angle::Result prepareForDispatch();
 
     MemoryProgramCache *getMemoryProgramCache() const { return mMemoryProgramCache; }
+    std::mutex &getProgramCacheMutex() const;
 
     bool hasBeenCurrent() const { return mHasBeenCurrent; }
     egl::Display *getDisplay() const { return mDisplay; }
diff --git a/src/libANGLE/Display.h b/src/libANGLE/Display.h
index 2b74d781c..19bd803f0 100644
--- a/src/libANGLE/Display.h
+++ b/src/libANGLE/Display.h
@@ -256,6 +256,7 @@ class Display final : public LabeledObject,
     egl::Error handleGPUSwitch();
 
     std::mutex &getDisplayGlobalMutex() { return mDisplayGlobalMutex; }
+    std::mutex &getProgramCacheMutex() { return mProgramCacheMutex; }
 
   private:
     Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice);
@@ -327,6 +328,7 @@ class Display final : public LabeledObject,
     std::vector<angle::ScratchBuffer> mZeroFilledBuffers;
 
     std::mutex mDisplayGlobalMutex;
+    std::mutex mProgramCacheMutex;
 };
 
 }  // namespace egl
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 5c8c6f19e..6abd836c9 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -1437,6 +1437,7 @@ angle::Result Program::linkImpl(const Context *context)
     // TODO: http://anglebug.com/4530: Enable program caching for separable programs
     if (cache && !isSeparable())
     {
+        std::lock_guard<std::mutex> cacheLock(context->getProgramCacheMutex());
         angle::Result cacheResult = cache->getProgram(context, this, &programHash);
         ANGLE_TRY(cacheResult);
 
@@ -1658,6 +1659,7 @@ void Program::resolveLinkImpl(const Context *context)
     postResolveLink(context);
 
     // Save to the program cache.
+    std::lock_guard<std::mutex> cacheLock(context->getProgramCacheMutex());
     MemoryProgramCache *cache = context->getMemoryProgramCache();
     // TODO: http://anglebug.com/4530: Enable program caching for separable programs
     if (cache && !isSeparable() &&