diff --git a/ChangeLog b/ChangeLog
index 96c58bb5..51ba4f90 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -71,6 +71,7 @@ ver. 0.10.6-dev (20??/??/??) - development edition
* parsing of action in jail-configs considers space between action-names as separator also
(previously only new-line was allowed), for example `action = a b` would specify 2 actions `a` and `b`
* new filter and jail for GitLab recognizing failed application logins (gh-2689)
+* new filter and jail for Grafana recognizing failed application logins (gh-2855)
* new filter and jail for SoftEtherVPN recognizing failed application logins (gh-2723)
* `filter.d/guacamole.conf` extended with `logging` parameter to follow webapp-logging if it's configured (gh-2631)
* `filter.d/bitwarden.conf` enhanced to support syslog (gh-2778)
diff --git a/config/filter.d/grafana.conf b/config/filter.d/grafana.conf
new file mode 100644
index 00000000..e7f0f420
--- /dev/null
+++ b/config/filter.d/grafana.conf
@@ -0,0 +1,9 @@
+# Fail2Ban filter for Grafana
+# Detecting unauthorized access
+# Typically logged in /var/log/grafana/grafana.log
+
+[Init]
+datepattern = ^t=%%Y-%%m-%%dT%%H:%%M:%%S%%z
+
+[Definition]
+failregex = ^(?: lvl=err?or)? msg="Invalid username or password"(?: uname=(?:"[^"]+"|\S+)| error="[^"]+"| \S+=(?:\S*|"[^"]+"))* remote_addr=$
diff --git a/config/jail.conf b/config/jail.conf
index 5ca67749..ddbcf61e 100644
--- a/config/jail.conf
+++ b/config/jail.conf
@@ -828,6 +828,10 @@ logpath = /usr/local/vpnserver/security_log/*/sec.log
port = http,https
logpath = /var/log/gitlab/gitlab-rails/application.log
+[grafana]
+port = http,https
+logpath = /var/log/grafana/grafana.log
+
[bitwarden]
port = http,https
logpath = /home/*/bwdata/logs/identity/Identity/log.txt
diff --git a/fail2ban/tests/files/logs/grafana b/fail2ban/tests/files/logs/grafana
new file mode 100644
index 00000000..aac86ebc
--- /dev/null
+++ b/fail2ban/tests/files/logs/grafana
@@ -0,0 +1,5 @@
+# Access of unauthorized host in /var/log/grafana/grafana.log
+# failJSON: { "time": "2020-10-19T17:44:33", "match": true , "host": "182.56.23.12" }
+t=2020-10-19T17:44:33+0200 lvl=eror msg="Invalid username or password" logger=context userId=0 orgId=0 uname= error="Invalid Username or Password" remote_addr=182.56.23.12
+# failJSON: { "time": "2020-10-19T18:44:33", "match": true , "host": "182.56.23.13" }
+t=2020-10-19T18:44:33+0200 lvl=eror msg="Invalid username or password" logger=context userId=0 orgId=0 uname= error="User not found" remote_addr=182.56.23.13