diff --git a/.gitignore b/.gitignore
index afd19c6e003dfddc99985617debd4b7845c0bd45..e2a3e9346c070336a189a33c39c09130942da8fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@ htmlcov
 .tox
 dist
 docs/build
+.coverage*
 
 # logs
 *.log
diff --git a/brian_dashboard_manager/grafana/organization.py b/brian_dashboard_manager/grafana/organization.py
index 629fe8a956187f021470fa3a610a3116e63b0246..eb2313f702582f60f40bbb6c21b89009bb9f5c7f 100644
--- a/brian_dashboard_manager/grafana/organization.py
+++ b/brian_dashboard_manager/grafana/organization.py
@@ -6,6 +6,7 @@ Grafana Organization management helpers.
 import logging
 import random
 import string
+from requests.exceptions import HTTPError
 from datetime import datetime
 from typing import Dict, List, Union
 
@@ -136,6 +137,78 @@ def delete_expired_api_tokens(request: AdminRequest) -> bool:
     return True
 
 
+def get_or_create_service_account(request: AdminRequest, org_id):
+    """
+    Gets a service account for the given organization, or creates one if it does not exist.
+
+    :param request: AdminRequest object
+    :param org_id: organization ID
+    :param name: service account name
+    :return: service account definition
+    """
+    switch_active_organization(request, org_id)
+
+    # get provision service account, if it exists
+    try:
+        service_accounts = request.get('api/serviceaccounts?perpage=10&page=1&query=provision').json()
+
+        if service_accounts and service_accounts.get('totalCount') > 0:
+            service_account = service_accounts.get('serviceAccounts')[0]
+            return service_account
+    except HTTPError as e:
+        if e.response.status_code != 404:
+            raise e
+
+    # create a service account for provisioning
+    try:
+        result = request.post(
+            'api/serviceaccounts', json={
+                'name': 'provision',
+                'role': 'Admin',
+                'isDisabled': False,
+            }).json()
+    except HTTPError as e:
+        print(e)
+
+    logger.info(f'Created provision service account for organization #{org_id}')
+    return result
+
+
+def create_service_account_token(request: AdminRequest, service_account_id: int):
+    """
+    Creates a new API token for the given service account.
+
+    :param request: AdminRequest object
+    :param service_account_id: service account ID
+    :return: Token definition
+    """
+    data = {
+        'name': f'provision-token-{datetime.now().isoformat()}',
+    }
+
+    result = request.post(f'api/serviceaccounts/{service_account_id}/tokens', json=data).json()
+    token_id = result.get('id')
+
+    logger.debug(f'Created API token #{token_id} for service account #{service_account_id}')
+
+    return result
+
+
+def delete_service_account(request: AdminRequest, service_account_id: int):
+    """
+    Deletes a service account with the given ID.
+
+    :param request: AdminRequest object
+    :param service_account_id: service account ID
+    :return: delete response
+    """
+
+    assert service_account_id is not None
+    result = request.delete(f'api/serviceaccounts/{service_account_id}')
+    logger.debug(f'Deleted service account #{service_account_id}')
+    return result
+
+
 def set_home_dashboard(request: TokenRequest, is_staff):
     """
     Sets the home dashboard for the organization
diff --git a/brian_dashboard_manager/grafana/provision.py b/brian_dashboard_manager/grafana/provision.py
index 5d9fae1a559455c706ba4bdb24b3b29f4f64b0e2..b9ce5bf75380851e942d6df1864780127818d410 100644
--- a/brian_dashboard_manager/grafana/provision.py
+++ b/brian_dashboard_manager/grafana/provision.py
@@ -18,7 +18,8 @@ from brian_dashboard_manager.services.api import fetch_services
 
 from brian_dashboard_manager.grafana.organization import \
     get_organizations, create_organization, create_api_token, \
-    delete_api_token, delete_expired_api_tokens, set_home_dashboard
+    delete_api_token, delete_expired_api_tokens, set_home_dashboard, \
+    get_or_create_service_account, delete_service_account, create_service_account_token
 from brian_dashboard_manager.grafana.dashboard import list_dashboards, \
     get_dashboard_definitions, create_dashboard, delete_dashboard
 from brian_dashboard_manager.grafana.datasource import \
@@ -814,10 +815,13 @@ def provision(config, raise_exceptions=False):
     """
 
     start = time.time()
-    tokens = []
+    accounts = []
     all_orgs = _provision_orgs(config)
     request = AdminRequest(**config)
-    delete_expired_api_tokens(request)
+    try:
+        delete_expired_api_tokens(request)
+    except Exception:
+        pass  # needed for older versions of grafana
 
     def _find_org_config(org):
         orgs_to_provision = config.get('organizations', DEFAULT_ORGANIZATIONS)
@@ -840,10 +844,17 @@ def provision(config, raise_exceptions=False):
                 # message logged from _find_org_config
                 continue
 
-            token = create_api_token(request, org_id)
+            try:
+                token = create_api_token(request, org_id)
+                accounts.append((org_id, token))
+            except Exception:
+                # create a service account for provisioning (>grafana 11.0)
+                account = get_or_create_service_account(request, org_id)
+                token = create_service_account_token(request, account['id'])
+                accounts.append((org_id, account))
+
             token_request = TokenRequest(token=token['key'], **config)
-            tokens.append((org_id, token['id']))
-            logger.debug(tokens)
+            logger.debug(accounts)
 
             all_original_dashboards = list_dashboards(token_request)
             all_original_dashboard_uids = {
@@ -902,7 +913,11 @@ def provision(config, raise_exceptions=False):
             folders_to_keep.update(ignored_folders)
 
             delete_unknown_folders(token_request, folders_to_keep)
-            delete_api_token(request, token['id'], org_id=org_id)
+            try:
+                delete_api_token(request, token['id'], org_id=org_id)
+            except Exception:
+                # we're on a newer version of grafana
+                delete_service_account(request, account['id'])
         except Exception:
             logger.exception(f'Error when provisioning org {org["name"]}')
             if raise_exceptions:
diff --git a/brian_dashboard_manager/templating/render.py b/brian_dashboard_manager/templating/render.py
index ac5b847b2ac9ebcd4e6f9b49c606ddf32d2853e6..8671e15421a1ccb18e3fd4d3d219c3133fa69013 100644
--- a/brian_dashboard_manager/templating/render.py
+++ b/brian_dashboard_manager/templating/render.py
@@ -262,11 +262,17 @@ def create_panel(
 def create_infobox():
     return {
         "datasource": None,
-        "gridPos": {"h": 1, "w": 24, "x": 0, "y": 0},
+        "gridPos": {"h": 2, "w": 24, "x": 0, "y": 0},
         "id": 1,
-        "options": {"content": "", "mode": "html"},
+        "options": {
+            "content": """
+            <center style="margin-top:5px;">
+                INFO: The average values displayed are only mean values for timescales of 2 days or less
+            </center>""",
+            "mode": "html"
+        },
         "pluginVersion": "8.2.5",
-        "title": "INFO: The average values displayed are only mean values for timescales of 2 days or less",
+        "title": "",
         "type": "text",
     }
 
diff --git a/changelog.md b/changelog.md
index 9da8f5c7de19168367e0deccc50af0500763957d..6eb8973c76359b0f674658976bcbbf618644d9e9 100644
--- a/changelog.md
+++ b/changelog.md
@@ -2,6 +2,9 @@
 
 All notable changes to this project will be documented in this file.
 
+## [0.65] - 2024-09-23
+- Support Grafana v11.3 layout & API changes
+
 ## [0.64] - 2024-08-14
 - POL1-841 - Promote NREN Access Beta and keep Legacy dashboard for GEANT staff
 
diff --git a/setup.py b/setup.py
index bad5488d8f9a33095612be037fee6e7e925dbb1b..be5db1ef6741eb993ae6a217bcbe2aafb3baaa7a 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
 
 setup(
     name='brian-dashboard-manager',
-    version="0.64",
+    version="0.65",
     author='GEANT',
     author_email='swd@geant.org',
     description='',
diff --git a/test/test_update.py b/test/test_update.py
index f4ab22416f295a72d9960a489f2e79b046ab6625..16800bf946b492b745e0d13ddabf1f365620e25a 100644
--- a/test/test_update.py
+++ b/test/test_update.py
@@ -778,7 +778,7 @@ def test_provision_re_peer_dashboard(
     panels = mock_grafana.dashboards_by_folder_uid[folder_uid][0]["panels"]
     expected_types = ["text", "graph", "graph", "row", "graph", "graph", "row"]
     assert [p["type"] for p in panels] == expected_types
-    assert "INFO" in panels[0]["title"]
+    assert "INFO" in panels[0]["options"]["content"]
     assert "ingress" in panels[1]["title"]
     assert "egress" in panels[2]["title"]
     assert "Services" in panels[3]["title"]