How to Reset Ghost Admin Password via Database

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 identifier
  • 10$ - 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_here with your desired password
  • The 10 is 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

  1. Go to your Ghost admin panel: https://your-site.com/ghost/
  2. Enter your email and new password
  3. 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

  1. Use strong passwords: At least 12 characters with mixed case, numbers, and symbols
  2. Don't store passwords in scripts: Use environment variables or enter manually
  3. Rotate database credentials: If you've exposed them, change them afterward
  4. Enable 2FA: Once logged in, enable two-factor authentication in Ghost settings
  5. 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 current directory
  • 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-Proto is 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