diff --git a/gdk/gdkglversionprivate.h b/gdk/gdkglversionprivate.h
index d947508..c0c3940 100644
--- gdk/gdkglversionprivate.h
+++ gdk/gdkglversionprivate.h
@@ -34,8 +34,8 @@ G_BEGIN_DECLS
 /* Minimum OpenGL versions supported by GTK.
  * Backends should make sure to never create a context of a previous version.
  */
-#define GDK_GL_MIN_GL_VERSION GDK_GL_VERSION_INIT (3, 3)
-#define GDK_GL_MIN_GLES_VERSION GDK_GL_VERSION_INIT (3, 0)
+#define GDK_GL_MIN_GL_VERSION GDK_GL_VERSION_INIT (2, 0)
+#define GDK_GL_MIN_GLES_VERSION GDK_GL_VERSION_INIT (2, 0)
 
 typedef struct _GdkGLVersion GdkGLVersion;
 
@@ -56,6 +56,11 @@ static const GdkGLVersion supported_gl_versions[] = {
   GDK_GL_VERSION_INIT (4, 1),
   GDK_GL_VERSION_INIT (4, 0),
   GDK_GL_VERSION_INIT (3, 3),
+  GDK_GL_VERSION_INIT (3, 2),
+  GDK_GL_VERSION_INIT (3, 1),
+  GDK_GL_VERSION_INIT (3, 0),
+  GDK_GL_VERSION_INIT (2, 1),
+  GDK_GL_VERSION_INIT (2, 0),
 
   GDK_GL_VERSION_INIT (0, 0)
 };
@@ -64,6 +69,7 @@ static const GdkGLVersion supported_gles_versions[] = {
   GDK_GL_VERSION_INIT (3, 2),
   GDK_GL_VERSION_INIT (3, 1),
   GDK_GL_VERSION_INIT (3, 0),
+  GDK_GL_VERSION_INIT (2, 0),
 
   GDK_GL_VERSION_INIT (0, 0)
 };

diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index c88236f..67c0205 100644
--- gdk/gdkglcontext.c
+++ gdk/gdkglcontext.c
@@ -109,6 +109,7 @@ const GdkDebugKey gdk_gl_feature_keys[] = {
   { "external-objects", GDK_GL_FEATURE_EXTERNAL_OBJECTS, "GL_EXT_memory_object and GL_EXT_semaphore"},
   { "external-objects-win32", GDK_GL_FEATURE_EXTERNAL_OBJECTS_WIN32, "GL_EXT_memory_object_win32 and GL_EXT_semaphore_win32" },
   { "blend-func-extended", GDK_GL_FEATURE_BLEND_FUNC_EXTENDED, "GL_EXT_blend_func_extended" },
+  { "sync", GDK_GL_FEATURE_SYNC, "GL_ARB_sync" },
 };
 
 typedef struct _GdkGLContextPrivate GdkGLContextPrivate;
@@ -1688,6 +1689,9 @@ gdk_gl_context_init_memory_flags (GdkGLContext *self)
   priv->memory_flags[GDK_MEMORY_G8A8] = GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE;
 #endif
 
+  if (!gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (3, 0)))
+    return;
+
   /* GLES 3.0.6 spec, table 3.13 */
   priv->memory_flags[GDK_MEMORY_G8] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_RENDERABLE | GDK_GL_FORMAT_FILTERABLE;
   priv->memory_flags[GDK_MEMORY_A8] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_RENDERABLE | GDK_GL_FORMAT_FILTERABLE;
@@ -1820,6 +1824,11 @@ gdk_gl_context_check_features (GdkGLContext *context)
       epoxy_has_gl_extension ("GL_EXT_blend_func_extended"))
     features |= GDK_GL_FEATURE_BLEND_FUNC_EXTENDED;
 
+  if (gdk_gl_context_check_version (context, "3.2", "3.0") ||
+      epoxy_has_gl_extension ("GL_ARB_sync") ||
+      epoxy_has_gl_extension ("GL_APPLE_sync"))
+    features |= GDK_GL_FEATURE_SYNC;
+
   return features;
 }
 
@@ -2070,8 +2079,12 @@ gdk_gl_context_get_glsl_version_string (GdkGLContext *self)
         return "#version 150";
       else if (gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (3, 1)))
         return "#version 140";
-      else
+      else if (gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (3, 0)))
         return "#version 130";
+      else if (gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (2, 1)))
+        return "#version 120";
+      else
+        return "#version 110";
     }
   else if (priv->api == GDK_GL_API_GLES)
     {
@@ -2196,7 +2209,9 @@ gdk_gl_context_has_vertex_arrays (GdkGLContext *self)
   switch (priv->api)
     {
     case GDK_GL_API_GL:
-      return TRUE;
+      return gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (3, 0)) ||
+             epoxy_has_gl_extension ("GL_ARB_vertex_array_object") ||
+             epoxy_has_gl_extension ("GL_APPLE_vertex_array_object");
 
     case GDK_GL_API_GLES:
       return gdk_gl_version_get_major (&priv->gl_version) >= 3;
diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h
index e0702f8..b73fc0e 100644
--- gdk/gdkglcontextprivate.h
+++ gdk/gdkglcontextprivate.h
@@ -35,6 +35,7 @@ typedef enum {
   GDK_GL_FEATURE_EXTERNAL_OBJECTS           = 1 << 3,
   GDK_GL_FEATURE_EXTERNAL_OBJECTS_WIN32     = 1 << 4,
   GDK_GL_FEATURE_BLEND_FUNC_EXTENDED        = 1 << 5,
+  GDK_GL_FEATURE_SYNC                       = 1 << 6,
 } GdkGLFeatures;
 
 #define GDK_GL_N_FEATURES 3

diff --git a/gdk/x11/gdkglcontext-glx.c b/gdk/x11/gdkglcontext-glx.c
index f7a028b..e6cb06d 100644
--- gdk/x11/gdkglcontext-glx.c
+++ gdk/x11/gdkglcontext-glx.c
@@ -187,7 +187,8 @@ gdk_x11_gl_context_glx_end_frame (GdkDrawContext *draw_context,
   gdk_x11_surface_pre_damage (surface);
 
 #ifdef HAVE_XDAMAGE
-  if (self->xdamage != 0 && _gdk_x11_surface_syncs_frames (surface))
+  if (self->xdamage != 0 && _gdk_x11_surface_syncs_frames (surface) &&
+      gdk_gl_context_has_feature (context, GDK_GL_FEATURE_SYNC))
     {
       g_assert (self->frame_fence == 0);
 
diff --git a/gsk/gpu/gskglframe.c b/gsk/gpu/gskglframe.c
index 38bd627..6479be9 100644
--- gsk/gpu/gskglframe.c
+++ gsk/gpu/gskglframe.c
@@ -321,7 +321,8 @@ gsk_gl_frame_submit (GskGpuFrame       *frame,
       op = gsk_gpu_op_gl_command (op, frame, &state);
     }
 
-  self->sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+  if (gdk_gl_context_has_feature (GDK_GL_CONTEXT(gsk_gpu_frame_get_context (frame)), GDK_GL_FEATURE_SYNC))
+    self->sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
 }
 
 static void
diff --git a/gsk/gpu/gskgpudownloadop.c b/gsk/gpu/gskgpudownloadop.c
index 72c6a7c..d3a0301 100644
--- gsk/gpu/gskgpudownloadop.c
+++ gsk/gpu/gskgpudownloadop.c
@@ -357,7 +357,10 @@ gsk_gpu_download_op_gl_command (GskGpuOp          *op,
    * the texture might survive the frame and its surface */
   data->context = g_object_ref (gdk_display_get_gl_context (gsk_gpu_device_get_display (gsk_gpu_frame_get_device (frame))));
   data->texture_id = texture_id;
-  data->sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+  if (gdk_gl_context_has_feature (data->context, GDK_GL_FEATURE_SYNC))
+    data->sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+  else
+    data->sync = NULL;
 
   builder = gdk_gl_texture_builder_new ();
   gdk_gl_texture_builder_set_context (builder, data->context);
diff --git a/gtk/gtkglarea.c b/gtk/gtkglarea.c
index 9460af7..8a17bb5 100644
--- gtk/gtkglarea.c
+++ gtk/gtkglarea.c
@@ -815,8 +815,11 @@ gtk_gl_area_snapshot (GtkWidget   *widget,
       priv->texture = NULL;
       priv->textures = g_list_prepend (priv->textures, texture);
 
-      sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-      gdk_gl_texture_builder_set_sync (texture->builder, sync);
+      if (gdk_gl_context_has_feature (priv->context, GDK_GL_FEATURE_SYNC))
+        {
+          sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+          gdk_gl_texture_builder_set_sync (texture->builder, sync);
+        }
 
       texture->gl_texture = gdk_gl_texture_builder_build (texture->builder,
                                                           release_gl_texture,
