How to Reset Ghost Admin Password via Database
When you've lost access to your Ghost admin account and can't use the email-based password reset, you can reset the password directly in the MySQL database.
Prerequisites
- SSH access to your Ghost server
- MySQL database credentials (found in Ghost's
config.production.json) - Node.js installed on the server
How Ghost Stores Passwords
Ghost uses bcrypt to hash passwords before storing them in the database. Bcrypt is a one-way hashing algorithm, meaning:
- Passwords cannot be "decrypted" - only verified
- Each hash includes a random salt for security
- The cost factor (default: 10) determines computational complexity
A bcrypt hash looks like this:
$2a$10$WHHHrCu0GMn4YM12bmRuoeseUh9qw5V792k50mbyJDZ/PeOFKG6lO
Breaking it down:
$2a$- bcrypt algorithm identifier10$- cost factor (2^10 = 1024 iterations)- Next 22 characters - the salt
- Remaining characters - the hashed password
Step 1: Find Your Database Credentials
SSH into your server and check Ghost's configuration:
cat /var/www/your-ghost-site/config.production.json
Look for the database section:
{
"database": {
"client": "mysql",
"connection": {
"host": "localhost",
"user": "ghost_user",
"password": "your_database_password",
"database": "your_database_name"
}
}
}
Step 2: Identify the User Account
Connect to MySQL and find the admin user:
mysql -u ghost_user -p your_database_name
Then run:
SELECT id, name, email, status FROM users WHERE status = 'active';
This will show you all active users and their email addresses.
Step 3: Generate a Bcrypt Hash
Ghost includes the bcryptjs library in its installation. Use it to generate a hash:
cd /var/www/your-ghost-site/current
node -e "
const bcrypt = require('bcryptjs');
const password = 'your_new_password_here';
const hash = bcrypt.hashSync(password, 10);
console.log(hash);
"
Important:
- Replace
your_new_password_herewith your desired password - The
10is the cost factor (higher = more secure but slower) - Save the output hash - you'll need it for the next step
Example output:
$2a$10$xYz123AbcDefGhiJklMnoPqrStUvWxYz456789AbCdEfGhIj
Step 4: Update the Password in Database
Connect to MySQL:
mysql -u ghost_user -p your_database_name
Update the password (replace the hash and email with your values):
UPDATE users
SET password = '$2a$10$xYz123AbcDefGhiJklMnoPqrStUvWxYz456789AbCdEfGhIj'
WHERE email = 'admin@example.com';
Verify the update:
SELECT email,
LEFT(password, 30) as password_preview
FROM users
WHERE email = 'admin@example.com';
Step 5: Test the Login
- Go to your Ghost admin panel:
https://your-site.com/ghost/ - Enter your email and new password
- You should now have access
One-Liner Command
For quick password resets, you can combine steps 3-4:
# Generate hash and update in one command
NEW_HASH=$(cd /var/www/your-ghost-site/current && node -e "
const bcrypt = require('bcryptjs');
console.log(bcrypt.hashSync('your_new_password', 10));
")
mysql -u ghost_user -p your_database_name -e "
UPDATE users SET password = '$NEW_HASH' WHERE email = 'admin@example.com';
"
Security Best Practices
- Use strong passwords: At least 12 characters with mixed case, numbers, and symbols
- Don't store passwords in scripts: Use environment variables or enter manually
- Rotate database credentials: If you've exposed them, change them afterward
- Enable 2FA: Once logged in, enable two-factor authentication in Ghost settings
- Check for unauthorized users: While in MySQL, verify no unknown users exist:
SELECT id, name, email, created_at FROM users;
Troubleshooting
"Access denied" when connecting to MySQL
- Verify credentials in
config.production.json - Check if MySQL is running:
sudo systemctl status mysql
Password still doesn't work after update
- Ensure you copied the full hash (no truncation)
- Check for extra spaces or characters
- Verify you updated the correct user:
SELECT * FROM users WHERE email = 'your@email.com';
bcryptjs module not found
- Make sure you're in the Ghost
currentdirectory - Try:
cd /var/www/your-ghost-site/current && npm ls bcryptjs
Hash has special characters causing SQL issues
- Escape the
$signs in bash:\$2a\$10\$... - Or use single quotes in MySQL client
"Failed to send email" error on login
Ghost may block login attempts and try to send a verification email. If email isn't configured, you'll see "Failed to send email. Please check your site configuration and try again."
Solution 1: Clear the brute force protection table
Ghost tracks failed login attempts in the brute table:
mysql -u ghost_user -p your_database_name
-- View current brute force records
SELECT * FROM brute;
-- Clear all records to reset login attempts
DELETE FROM brute;
Solution 2: Disable staff device verification
Ghost's staffDeviceVerification feature requires email confirmation for new device logins. Disable it in config.production.json:
nano /var/www/your-ghost-site/config.production.json
Find and change:
{
"security": {
"staffDeviceVerification": false
}
}
If the security section doesn't exist, add it after the mail section.
Then restart Ghost:
# Using Ghost CLI
cd /var/www/your-ghost-site && ghost restart
# Or using systemd directly
sudo systemctl restart ghost_your-site-name
Combined fix script:
# 1. Clear brute force table
mysql -u ghost_user -p your_database_name -e "DELETE FROM brute;"
# 2. Disable device verification
sed -i 's/"staffDeviceVerification": true/"staffDeviceVerification": false/' \
/var/www/your-ghost-site/config.production.json
# 3. Restart Ghost
sudo systemctl restart ghost_your-site-name
Login works but immediately logs out
This can happen if cookies aren't being set correctly. Check:
- Your domain configuration in
config.production.json - Nginx proxy headers (ensure
X-Forwarded-Protois set) - Browser cookie settings
Alternative: Using Ghost CLI
If you have Ghost CLI access and email is configured:
cd /var/www/your-ghost-site
ghost run -e "
const models = require('./current/core/server/models');
models.init().then(() => {
return models.User.edit({password: 'new_password'}, {id: 1});
}).then(() => console.log('Done'));
"
However, the database method is more reliable when Ghost CLI has issues.
Last updated: January 2026
Tested with Ghost 6.7.0, MySQL 8.0