diff --git a/brian_dashboard_manager/config.py b/brian_dashboard_manager/config.py
index c5a828e0573c376726a1ad02e6d8655eb2d9dbbc..e167231f1208f3c27f304d4b1bb6fc1ca63bf721 100644
--- a/brian_dashboard_manager/config.py
+++ b/brian_dashboard_manager/config.py
@@ -30,6 +30,8 @@ If the value is a list, dashboard titles within the list should be excluded.
 import json
 import jsonschema
 
+STATE_PATH = '/tmp/briandashboardmanager-state.json'
+
 DEFAULT_ORGANIZATIONS = [
     {
         "name": "GÉANT Staff",
diff --git a/brian_dashboard_manager/grafana/provision.py b/brian_dashboard_manager/grafana/provision.py
index b16f773d63e84518465a179471c7a96d2a3e6608..685be93971bbd9b49ea946a4ea1748331c4ee79a 100644
--- a/brian_dashboard_manager/grafana/provision.py
+++ b/brian_dashboard_manager/grafana/provision.py
@@ -4,8 +4,10 @@ entire provisioning lifecycle.
 """
 import logging
 import time
+import json
+import datetime
 from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
-from brian_dashboard_manager.config import DEFAULT_ORGANIZATIONS
+from brian_dashboard_manager.config import DEFAULT_ORGANIZATIONS, STATE_PATH
 from brian_dashboard_manager.grafana.utils.request import \
     AdminRequest, \
     TokenRequest
@@ -94,6 +96,23 @@ def provision_aggregate(token_request, agg_type, aggregate_folder,
     create_dashboard(token_request, rendered, aggregate_folder['id'])
 
 
+def provision_maybe(config):
+    with open(STATE_PATH, 'r+') as f:
+        def write_timestamp(timestamp, provisioning):
+            f.seek(0)
+            f.write(json.dumps(
+                {'timestamp': timestamp, 'provisioning': provisioning}))
+            f.truncate()
+
+        try:
+            now = datetime.datetime.now()
+            write_timestamp(now.timestamp(), True)
+            provision(config)
+        finally:
+            now = datetime.datetime.now()
+            write_timestamp(now.timestamp(), False)
+
+
 def provision(config):
 
     request = AdminRequest(**config)
diff --git a/brian_dashboard_manager/routes/update.py b/brian_dashboard_manager/routes/update.py
index ed538e41ebe6f161dea5235e464537b0a8ac3908..780d40d6affb7aa7784273df23d6760e2830902f 100644
--- a/brian_dashboard_manager/routes/update.py
+++ b/brian_dashboard_manager/routes/update.py
@@ -1,8 +1,14 @@
+import json
+import datetime
+from flask import jsonify, Response
 from concurrent.futures import ThreadPoolExecutor
+from json.decoder import JSONDecodeError
 from flask import Blueprint, current_app
 from brian_dashboard_manager.routes import common
-from brian_dashboard_manager.grafana.provision import provision
+from brian_dashboard_manager.grafana.provision import provision_maybe
 from brian_dashboard_manager import CONFIG_KEY
+from brian_dashboard_manager.config import STATE_PATH
+
 
 routes = Blueprint("update", __name__)
 
@@ -22,6 +28,25 @@ def after_request(resp):
     return common.after_request(resp)
 
 
+def should_provision():
+    try:
+        with open(STATE_PATH, 'r+') as f:
+            try:
+                state = json.load(f)
+            except JSONDecodeError:
+                state = {}
+
+            provisioning = state.get('provisioning', False)
+            timestamp = datetime.datetime.fromtimestamp(
+                state.get('timestamp', 1))
+
+            can_provision = not provisioning
+            return can_provision, timestamp
+    except FileNotFoundError:
+        with open(STATE_PATH, 'w') as f:
+            return True, None
+
+
 @routes.route('/', methods=['GET'])
 def update():
     """
@@ -37,6 +62,11 @@ def update():
 
     :return: json
     """
-    executor = ThreadPoolExecutor(max_workers=1)
-    executor.submit(provision, current_app.config[CONFIG_KEY])
-    return {'data': {'message': 'Provisioning dashboards!'}}
+    should, timestamp = should_provision()
+    if should:
+        executor = ThreadPoolExecutor(max_workers=1)
+        executor.submit(provision_maybe, current_app.config[CONFIG_KEY])
+        return jsonify({'data': {'message': 'Provisioning dashboards!'}})
+    else:
+        message = f'Provision already in progress since {timestamp}'
+        return Response(message, status=503)