diff --git a/.env.dist b/.env.dist
index 3d1b90bbdb650736d11ec8b6471aa09bfed3b13d..e22ca4d8eec49b19437abcdfec8276b092b77161 100644
--- a/.env.dist
+++ b/.env.dist
@@ -3,6 +3,8 @@
 # MYSQL_PASSWORD=""
 # MYSQL_DATABASE=""
 
+# DEBUG_BAR="1" // Enable to display the debug bar in development mode
+
 # STUDIP_CACHING_ENABLE=""
 # STUDIP_CACHE_IS_SESSION_STORAGE=""
 # STUDIP_ENV=""
diff --git a/app/controllers/debugbar.php b/app/controllers/debugbar.php
new file mode 100644
index 0000000000000000000000000000000000000000..a80000d86d89bef62afb208f9d551df9693b7295
--- /dev/null
+++ b/app/controllers/debugbar.php
@@ -0,0 +1,17 @@
+<?php
+final class DebugbarController extends Trails_Controller
+{
+    public function css_action(): void
+    {
+        $this->set_content_type('text/css;charset=utf-8');
+        $this->render_nothing();
+        app()->get(DebugBar\DebugBar::class)->getJavascriptRenderer()->dumpCssAssets();
+    }
+
+    public function js_action(): void
+    {
+        $this->set_content_type('text/javascript;charset=utf-8');
+        $this->render_nothing();
+        app()->get(DebugBar\DebugBar::class)->getJavascriptRenderer()->setIncludeVendors(false)->dumpJsAssets();
+    }
+}
diff --git a/composer.json b/composer.json
index 8ec6778ed794023c3b433aa4ba795d14b3f07f4e..bd01b2840e9dd4eeb8ed590739fb01222e1fedd6 100644
--- a/composer.json
+++ b/composer.json
@@ -13,7 +13,8 @@
         "codeception/module-asserts": "3.0.0",
         "overtrue/phplint": "9.3.0",
         "phpstan/phpstan": "1.11.0",
-        "symfony/var-dumper": "6.4.7"
+        "symfony/var-dumper": "6.4.7",
+        "maximebf/debugbar": "1.22.3"
     },
     "require": {
         "php": "^8.1",
diff --git a/composer.lock b/composer.lock
index f2e656db651a26a13a3e8fc29307c3996a643fce..2392a4089fd30827eff521728f6cbc0e74121a75 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "7b19d8591a65485c94fb1794c93eef90",
+    "content-hash": "3cab15d3a1cd08dde4cd02d5bb19c760",
     "packages": [
         {
             "name": "algo26-matthias/idna-convert",
@@ -5496,6 +5496,74 @@
             },
             "time": "2024-02-02T19:21:00+00:00"
         },
+        {
+            "name": "maximebf/debugbar",
+            "version": "v1.22.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/maximebf/php-debugbar.git",
+                "reference": "7aa9a27a0b1158ed5ad4e7175e8d3aee9a818b96"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/7aa9a27a0b1158ed5ad4e7175e8d3aee9a818b96",
+                "reference": "7aa9a27a0b1158ed5ad4e7175e8d3aee9a818b96",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2|^8",
+                "psr/log": "^1|^2|^3",
+                "symfony/var-dumper": "^4|^5|^6|^7"
+            },
+            "require-dev": {
+                "dbrekelmans/bdi": "^1",
+                "phpunit/phpunit": "^8|^9",
+                "symfony/panther": "^1|^2.1",
+                "twig/twig": "^1.38|^2.7|^3.0"
+            },
+            "suggest": {
+                "kriswallsmith/assetic": "The best way to manage assets",
+                "monolog/monolog": "Log using Monolog",
+                "predis/predis": "Redis storage"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.22-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "DebugBar\\": "src/DebugBar/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Maxime Bouroumeau-Fuseau",
+                    "email": "maxime.bouroumeau@gmail.com",
+                    "homepage": "http://maximebf.com"
+                },
+                {
+                    "name": "Barry vd. Heuvel",
+                    "email": "barryvdh@gmail.com"
+                }
+            ],
+            "description": "Debug bar in the browser for php application",
+            "homepage": "https://github.com/maximebf/php-debugbar",
+            "keywords": [
+                "debug",
+                "debugbar"
+            ],
+            "support": {
+                "issues": "https://github.com/maximebf/php-debugbar/issues",
+                "source": "https://github.com/maximebf/php-debugbar/tree/v1.22.3"
+            },
+            "time": "2024-04-03T19:39:26+00:00"
+        },
         {
             "name": "myclabs/deep-copy",
             "version": "1.11.1",
diff --git a/lib/bootstrap-definitions.php b/lib/bootstrap-definitions.php
index d34d0231dbb7b15b90612520f70ad8fbaa63ea2c..2f59dc9bffc897f6a7632a4ab047e04f419d7305 100644
--- a/lib/bootstrap-definitions.php
+++ b/lib/bootstrap-definitions.php
@@ -1,10 +1,18 @@
 <?php
 
+use DebugBar\DataCollector\ExceptionsCollector;
+use DebugBar\DataCollector\MemoryCollector;
+use DebugBar\DataCollector\MessagesCollector;
+use DebugBar\DataCollector\PhpInfoCollector;
+use DebugBar\DataCollector\RequestDataCollector;
+use DebugBar\DataCollector\TimeDataCollector;
 use Monolog\Handler\StreamHandler;
 use Monolog\Logger;
 use Psr\Container\ContainerInterface;
 use Psr\Log\LoggerInterface;
 
+use function DI\create;
+
 return [
     LoggerInterface::class => DI\factory(function () {
         return new Logger('studip', [
@@ -17,10 +25,46 @@ return [
     \Studip\Cache\Cache::class => DI\factory(function () {
         return \Studip\Cache\Factory::getCache();
     }),
-    StudipPDO::class => DI\factory(function () {
+    PDO::class => DI\factory(function () {
         return DBManager::get();
     }),
     Trails\Dispatcher::class => DI\factory(function (ContainerInterface $container) {
         return new \StudipDispatcher($container);
     }),
+    DebugBar\DebugBar::class => DI\factory(function (ContainerInterface $container) {
+        $debugBar = new DebugBar\DebugBar();
+        $debugBar->addCollector(new PhpInfoCollector());
+        $debugBar->addCollector(new RequestDataCollector());
+        $debugBar->addCollector(new MemoryCollector());
+        $debugBar->addCollector(new ExceptionsCollector());
+
+        // Future Improvements, not used/activated right now
+        # $debugBar->addCollector(new MessagesCollector());
+        # $debugBar->addCollector(new TimeDataCollector());
+
+        $config = iterator_to_array(Config::getInstance()->getIterator());
+        ksort($config);
+        $debugBar->addCollector(new DebugBar\DataCollector\ConfigCollector($config));
+
+        $pdo = $container->get(PDO::class);
+        if ($pdo instanceof DebugBar\DataCollector\PDO\TraceablePDO) {
+            $collector = new DebugBar\DataCollector\PDO\PDOCollector($pdo);
+            $debugBar->addCollector($collector);
+        }
+
+        return $debugBar;
+    }),
+    StudipPDO::class => DI\factory(function () {
+        $pdo = new StudipPDO(
+            "mysql:host={$GLOBALS['DB_STUDIP_HOST']};dbname={$GLOBALS['DB_STUDIP_DATABASE']};charset=utf8mb4",
+            $GLOBALS['DB_STUDIP_USER'],
+            $GLOBALS['DB_STUDIP_PASSWORD']
+        );
+
+        if (Studip\Debug\DebugBar::isActivated()) {
+            $pdo = new DebugBar\DataCollector\PDO\TraceablePDO($pdo);
+        }
+
+        return $pdo;
+    }),
 ];
diff --git a/lib/bootstrap.php b/lib/bootstrap.php
index e9c9bb5c702d677863a78dc9d32417a43843cd6d..8c618ff7d5a240468f9989088939f256c7e0d88d 100644
--- a/lib/bootstrap.php
+++ b/lib/bootstrap.php
@@ -129,13 +129,10 @@ $GLOBALS['template_factory'] = new Flexi\Factory("{$STUDIP_BASE_PATH}/templates"
 
 // set default pdo connection
 try {
-    DBManager::getInstance()
-        ->setConnection('studip',
-            'mysql:host=' . $GLOBALS['DB_STUDIP_HOST'] .
-            ';dbname=' . $GLOBALS['DB_STUDIP_DATABASE'] .
-            ';charset=utf8mb4',
-            $GLOBALS['DB_STUDIP_USER'],
-            $GLOBALS['DB_STUDIP_PASSWORD']);
+    DBManager::getInstance()->setConnection(
+        'studip',
+        app(StudipPDO::class)
+    );
 } catch (PDOException $exception) {
     if (Studip\ENV === 'development') {
         throw $exception;
diff --git a/lib/classes/Debug/DebugBar.php b/lib/classes/Debug/DebugBar.php
new file mode 100644
index 0000000000000000000000000000000000000000..bbd80c9f13fce2d026b435fe86a3573e79338352
--- /dev/null
+++ b/lib/classes/Debug/DebugBar.php
@@ -0,0 +1,12 @@
+<?php
+namespace Studip\Debug;
+
+final class DebugBar
+{
+    public static function isActivated(): bool
+    {
+        return \Studip\ENV === 'development'
+            && ($_ENV['DEBUG_BAR'] ?? false)
+            && class_exists(\DebugBar\DebugBar::class);
+    }
+}
diff --git a/lib/classes/Debug/TrailsCollector.php b/lib/classes/Debug/TrailsCollector.php
new file mode 100644
index 0000000000000000000000000000000000000000..f4b8a65073ad15b4f207470ea740e237a9a723ef
--- /dev/null
+++ b/lib/classes/Debug/TrailsCollector.php
@@ -0,0 +1,69 @@
+<?php
+namespace Studip\Debug;
+
+use DebugBar\DataCollector\DataCollector;
+use DebugBar\DataCollector\Renderable;
+use Trails\Controller;
+
+final class TrailsCollector extends DataCollector implements Renderable
+{
+    public function __construct(
+        private readonly Controller $controller
+    ) {
+        $this->useHtmlVarDumper(false);
+    }
+
+    public function collect()
+    {
+        $data = [];
+        foreach ($this->controller->get_assigned_variables() as $k => $v) {
+            if ($this->isHtmlVarDumperUsed()) {
+                $v = $this->getVarDumper()->renderVar($v);
+            } else if (!is_string($v)) {
+                $v = $this->getDataFormatter()->formatVar($v);
+            }
+            $data[$k] = $v;
+        }
+
+        ksort($data);
+
+        return $data;
+    }
+
+    public function getName()
+    {
+        return 'trails';
+    }
+
+    /**
+     * @return array
+     */
+    public function getAssets()
+    {
+        return $this->isHtmlVarDumperUsed() ? $this->getVarDumper()->getAssets() : [];
+    }
+
+    /**
+     * @return array[]
+     */
+    public function getWidgets()
+    {
+        $name = $this->getName();
+        $widget = $this->isHtmlVarDumperUsed()
+            ? 'PhpDebugBar.Widgets.HtmlVariableListWidget'
+            : 'PhpDebugBar.Widgets.VariableListWidget';
+
+        return [
+            $name => [
+                'icon'   => 'code',
+                'widget' => $widget,
+                'map' => $name,
+                'default' => '{}'
+            ],
+            "{$name}:badge" => [
+                'map' => "{$name}:variable__count",
+                'default' => count($this->controller->get_assigned_variables()),
+            ],
+        ];
+    }
+}
diff --git a/lib/classes/PageLayout.php b/lib/classes/PageLayout.php
index d3f3028d524b55c02cace5b7afd94fe2246bfd28..a4178a5abdba111ee2ca92529fbba8c3a2a68f70 100644
--- a/lib/classes/PageLayout.php
+++ b/lib/classes/PageLayout.php
@@ -139,6 +139,21 @@ class PageLayout
         self::addScript('studip-wysiwyg.js?v=' . $v);
 
         self::addStylesheet('print.css?v=' . $v, ['media' => 'print']);
+
+        if (Studip\Debug\DebugBar::isActivated()) {
+            $old_base = URLHelper::setBaseURL($GLOBALS['ABSOLUTE_URI_STUDIP']);
+
+            self::addHeadElement('link', [
+                'href' => URLHelper::getURL('dispatch.php/debugbar/css'),
+                'rel' => 'stylesheet',
+                'type' => 'text/css',
+            ]);
+            self::addHeadElement('script', [
+                'src' => URLHelper::getURL('dispatch.php/debugbar/js'),
+            ]);
+
+            URLHelper::setBaseURL($old_base);
+        }
     }
 
     /**
diff --git a/lib/classes/StudipController.php b/lib/classes/StudipController.php
index 4fbcc429ef96883df630d556dd0ee8a181b4418c..0643836c6b632fb6b97e912417692baaa291a5f2 100644
--- a/lib/classes/StudipController.php
+++ b/lib/classes/StudipController.php
@@ -9,6 +9,7 @@
  * the License, or (at your option) any later version.
  */
 
+use DebugBar\DebugBar;
 use PhpOffice\PhpSpreadsheet\Spreadsheet;
 use PhpOffice\PhpSpreadsheet\Writer\Csv;
 use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
@@ -294,7 +295,7 @@ abstract class StudipController extends Trails\Controller
 
         // Extract fragment (if any)
         if (strpos($to, '#') !== false) {
-            list($args[0], $fragment) = explode('#', $to);
+            [$args[0], $fragment] = explode('#', $to);
         }
 
         // Extract parameters (if any)
@@ -666,6 +667,19 @@ abstract class StudipController extends Trails\Controller
         return $this->response;
     }
 
+    public function render_template($template_name, $layout = null)
+    {
+        if (Studip\Debug\DebugBar::isActivated()) {
+            $debugbar = app()->get(Debugbar::class);
+            if (!isset($debugbar['trails'])) {
+                $collector = new \Studip\Debug\TrailsCollector($this);
+                $debugbar->addCollector($collector);
+            }
+        }
+
+        parent::render_template($template_name, $layout);
+    }
+
     /**
      * Renders a given template and returns the resulting string.
      *
diff --git a/templates/layouts/base.php b/templates/layouts/base.php
index 2db1f7eab8b4813799ade93694197e9346c1e225..cd32e3b656f5864f1537b338ee7ab28a04a91235 100644
--- a/templates/layouts/base.php
+++ b/templates/layouts/base.php
@@ -103,6 +103,12 @@ $lang_attr = str_replace('_', '-', $_SESSION['_language']);
     <?= $this->render_partial('footer', ['link_params' => $header_template->link_params]); ?>
     <?= SkipLinks::getHTML() ?>
     <section class="sr-only" id="notes_for_screenreader" aria-live="polite"></section>
+
+<?php
+if (Studip\Debug\DebugBar::isActivated()) {
+    echo app()->get(\DebugBar\DebugBar::class)->getJavascriptRenderer()->render();
+}
+?>
 </body>
 </html>
 <?php NotificationCenter::postNotification('PageDidRender', PageLayout::getBodyElementId());