Fixing a grafana instance on macOS
Date: 2026-02-08
Host: server (macOS Monterey; Homebrew prefix: /usr/local)
Grafana install: Homebrew (/usr/local/opt/grafana)
Grafana data: /usr/local/var/lib/grafana
Grafana (Homebrew on macOS Monterey) & Password Reset + Boot-Time Startup (No GUI Login)
Summary of the fix
- The admin password did not work, even after reset attempts.
- Grafana ran manually, but it did not run reliably as a user service through
brew services. The service needed to start at boot without a desktop login. - We fixed both problems:
- Reset the password against the actual Brew paths and database that the running server uses.
- Replace the GUI-bound LaunchAgent approach with a system LaunchDaemon at
/Library/LaunchDaemons/...that runs at boot as your user.
Caveats
The password reset reported success but used the wrong database
You can point Grafana at different data directories. In this setup, the running Brew Grafana server uses:
- Data dir:
/usr/local/var/lib/grafana - SQLite DB:
/usr/local/var/lib/grafana/grafana.db - Logs:
/usr/local/var/log/grafana - Plugins:
/usr/local/var/lib/grafana/plugins - Homepath (defaults.ini lives here):
/usr/local/opt/grafana/share/grafana
Earlier attempts reset the password with Grafana’s default data directory under the install tree. Some attempts did not override the paths. These attempts could target:
/usr/local/opt/grafana/share/grafana/data
The CLI reported success. But the running server still used the original database at /usr/local/var/lib/grafana. So the login still failed.
Grafana v12 changed the CLI behavior, and the flags differ between server and cli
On Grafana v12, the correct CLI is:
- ✅
/usr/local/opt/grafana/bin/grafana cli ...
But the --packaging=brew flag:
- ✅ valid for
grafana server - ❌ NOT valid for
grafana cli(saw:flag provided but not defined: -packaging)
So I used --configOverrides for the CLI instead of --packaging=brew.
brew services uses LaunchAgents in the GUI login domain
Homebrew services normally create a LaunchAgent at:
~/Library/LaunchAgents/homebrew.mxcl.grafana.plist
LaunchAgents are tied to a user session. They can fail in these cases:
- Nobody is logged into the GUI.
- The system reboots or respawns the agent.
- Permissions or environment variables differ from an interactive shell.
The goal was to start Grafana at boot with no GUI login. That requires a LaunchDaemon in the system domain:
/Library/LaunchDaemons/...
Root and Brew do not mix
brew as root produced this error:
Error: Need to download ... but cannot as root!
So the final boot-time solution does not use brew at all.
Evidence: confirm which DB/path Grafana is actually using
This log confirms the running server points at the Brew var paths:
grep -E 'Path Data|Connecting to DB|dbtype=sqlite3' /usr/local/var/log/grafana/grafana.log | tail -n 20
Expected (and observed) patterns:
Path Data path=/usr/local/var/lib/grafanaConnecting to DB dbtype=sqlite3
Fix 1: Reset the admin password correctly (Grafana v12 and Homebrew paths)
1.1 Verify defaults.ini exists under the homepath
Grafana needs conf/defaults.ini under the homepath you pass:
ls -la /usr/local/opt/grafana/share/grafana/conf/defaults.ini
1.2 Run the password reset against the correct homepath + config + overrides
Critical details:
- Run from the homepath directory (or set
--homepathcorrectly) - Use your Brew config:
/usr/local/etc/grafana/grafana.ini - Override the default paths so the CLI hits
/usr/local/var/lib/grafana/grafana.db
cd /usr/local/opt/grafana/share/grafana
/usr/local/opt/grafana/bin/grafana cli --homepath /usr/local/opt/grafana/share/grafana --config /usr/local/etc/grafana/grafana.ini --configOverrides "cfg:default.paths.data=/usr/local/var/lib/grafana cfg:default.paths.logs=/usr/local/var/log/grafana cfg:default.paths.plugins=/usr/local/var/lib/grafana/plugins" admin reset-admin-password 'fuckface'
Expected success message:
Admin password changed successfully ✅
1.3 Confirm the admin user in the correct DB
sqlite3 /usr/local/var/lib/grafana/grafana.db "select id,login,email,is_admin,is_disabled from user order by id limit 20;"
Expected output (as observed):
1|admin|admin@localhost|1|0
1.4 Confirm Grafana is listening and responding
curl -sSI http://127.0.0.1:3000/login | head
netstat -anv | grep '\.3000 ' | grep LISTEN
Fix 2: Start Grafana at boot with no desktop login, with a LaunchDaemon
Why a system LaunchDaemon instead of the brew services LaunchAgent
- LaunchAgent: user GUI login domain. Unreliable without a login session.
- LaunchDaemon: system boot domain. Runs at startup even with no GUI login.
We created our own LaunchDaemon plist:
- Path:
/Library/LaunchDaemons/com.grafana.server.plist - Runs as user:
iciadmin(not root)
The LaunchDaemon plist
File: /Library/LaunchDaemons/com.grafana.server.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.grafana.server</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<!-- Run Grafana as a normal user -->
<key>UserName</key>
<string>iciadmin</string>
<key>GroupName</key>
<string>admin</string>
<!-- Must be the Grafana homepath (contains conf/defaults.ini) -->
<key>WorkingDirectory</key>
<string>/usr/local/opt/grafana/share/grafana</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/opt/grafana/bin/grafana</string>
<string>server</string>
<string>--config</string>
<string>/usr/local/etc/grafana/grafana.ini</string>
<string>--homepath</string>
<string>/usr/local/opt/grafana/share/grafana</string>
<!-- Valid for grafana server -->
<string>--packaging=brew</string>
<!-- Force Homebrew paths -->
<string>cfg:default.paths.data=/usr/local/var/lib/grafana</string>
<string>cfg:default.paths.logs=/usr/local/var/log/grafana</string>
<string>cfg:default.paths.plugins=/usr/local/var/lib/grafana/plugins</string>
</array>
<!-- launchd logs -->
<key>StandardOutPath</key>
<string>/usr/local/var/log/grafana/launchd.out</string>
<key>StandardErrorPath</key>
<string>/usr/local/var/log/grafana/launchd.err</string>
</dict>
</plist>
Commands used to create and enable the LaunchDaemon
2.1 Create the plist (as root via doas)
doas tee /Library/LaunchDaemons/com.grafana.server.plist >/dev/null <<'PLIST'
[...XML CONTENT AS SHOWN ABOVE...]
PLIST
2.2 Set required ownership and permissions
LaunchDaemons must be owned by root:wheel and mode 0644:
doas chown root:wheel /Library/LaunchDaemons/com.grafana.server.plist
doas chmod 644 /Library/LaunchDaemons/com.grafana.server.plist
2.3 Ensure the log directory exists and is writable by the Grafana user
doas mkdir -p /usr/local/var/log/grafana
doas chown -R iciadmin:admin /usr/local/var/log/grafana
doas chmod 775 /usr/local/var/log/grafana
2.4 Fix the SQLite DB permission warning
Grafana warned that the DB file had broader permissions than expected. We corrected it:
doas chmod 640 /usr/local/var/lib/grafana/grafana.db
doas chown iciadmin:admin /usr/local/var/lib/grafana/grafana.db
2.5 Load and enable the daemon (system domain)
If you repeat this step, unload the daemon first. This step is safe:
doas launchctl bootout system /Library/LaunchDaemons/com.grafana.server.plist 2>/dev/null || true
Then load + enable:
doas launchctl bootstrap system /Library/LaunchDaemons/com.grafana.server.plist
doas launchctl enable system/com.grafana.server
Verification that it worked
3.1 Confirm launchd sees it and it is running
doas launchctl print system/com.grafana.server | sed -n '1,200p'
Expected highlights:
domain = systemstate = runningusername = iciadminworking directory = /usr/local/opt/grafana/share/grafanaarguments = ...(showsgrafana server ... cfg:default.paths.*)
3.2 Confirm Grafana responds locally
curl -sSI http://127.0.0.1:3000/login | head
Expected:
HTTP/1.1 200 OK
Where everything lives (paths)
Homebrew/Grafana
- Binary:
/usr/local/opt/grafana/bin/grafana - Homepath:
/usr/local/opt/grafana/share/grafana - Config:
/usr/local/etc/grafana/grafana.ini
Data (critical)
- Data dir:
/usr/local/var/lib/grafana - DB:
/usr/local/var/lib/grafana/grafana.db - Plugins:
/usr/local/var/lib/grafana/plugins
Logs
- Grafana log:
/usr/local/var/log/grafana/grafana.log - launchd stdout:
/usr/local/var/log/grafana/launchd.out - launchd stderr:
/usr/local/var/log/grafana/launchd.err
Boot-time startup definition
- LaunchDaemon plist:
/Library/LaunchDaemons/com.grafana.server.plist
Common failure modes (quick triage)
The LaunchDaemon does not load
- Check the plist ownership and permissions. They must be
root:wheeland0644. - Check the logs:
tail -n 200 /usr/local/var/log/grafana/launchd.err
tail -n 200 /usr/local/var/log/grafana/grafana.log
Grafana runs but the login fails again
- Verify the server uses the expected database:
grep -E 'Path Data|Connecting to DB' /usr/local/var/log/grafana/grafana.log | tail -n 5
- Run the password reset again with the same overrides used here.
brew services still shows error 78
That is the old user LaunchAgent path. It is not needed once the LaunchDaemon is in place.
The final setup does not rely on brew services for boot-time behavior.
Final outcome
- We reset the admin password in the correct SQLite database used by the running Brew instance.
- Grafana now starts at system boot as user
iciadmin, with no GUI login, through a custom LaunchDaemon.