Files
pgsql-jellyfin/docs/README-POSTGRESQL.md
wjones 3e5d29225a Refactor SQLite Database Provider
- Removed unused classes and files related to SQLite database provider, including SqliteDesignTimeJellyfinDbFactory, ModelBuilderExtensions, PragmaConnectionInterceptor, AssemblyInfo, SqliteDatabaseProvider, DateTimeKindValueConverter.
- Updated tests to remove dependencies on removed classes and adjusted mocking for configuration sections.
- Added Microsoft.EntityFrameworkCore.Sqlite package reference to test project.
- Improved string handling in tests for better consistency and clarity.
- Refactored logging methods in JellyfinApplicationFactory for better readability and maintainability.
2026-05-03 09:39:00 -04:00

15 KiB

Jellyfin with PostgreSQL Support

This is a fork of Jellyfin that adds PostgreSQL database support for .NET 11 preview.

Features

  • PostgreSQL database provider implementation
  • Automatic database initialization from SQL scripts
  • Remote database support with connection string configuration
  • Database backup/restore via pg_dump/pg_restore
  • Migration system disabled in favor of SQL scripts
  • Support for both local and remote PostgreSQL servers

Requirements

FFmpeg Requirements

jellyfin-ffmpeg is highly preferred and recommended for use with Jellyfin Media Server. While standard FFmpeg can be used, the custom jellyfin-ffmpeg fork includes specifically targeted fixes, optimizations, and enhanced hardware acceleration support for media streaming that may not be available or prioritized in the upstream version.

Why jellyfin-ffmpeg is Preferred:

  • Improved Hardware Acceleration: Better support for hardware acceleration (NVENC, QuickSync, VA-API) across a wider range of GPUs, reducing the risk of partial acceleration
  • Reduced Playback Issues: Specifically built to handle HDR/Dolby Vision content, HLS/fMP4/MPEG-TS streaming, and complex transcoding scenarios better than standard FFmpeg
  • Optimized Performance: Often includes more efficient software decoders (like dav1d for AV1)
  • Pre-configured: Automatically included with official Docker images, deb packages, and Windows installers

Link: jellyfin-ffmpeg repository

Installation:

Debian/Ubuntu (using Jellyfin repository):

# Add Jellyfin repository (if not already added)
sudo apt-get install -y software-properties-common
sudo add-apt-repository universe

# Install jellyfin-ffmpeg
sudo apt-get update
sudo apt-get install -y jellyfin-ffmpeg6

Manual Download: Download from jellyfin-ffmpeg releases and configure the path in Jellyfin settings.

If using a custom or unofficial installation where jellyfin-ffmpeg is not available, standard FFmpeg might work but could lead to issues with specific transcoding tasks:

# Debian/Ubuntu
sudo apt-get install -y ffmpeg

# RHEL/Fedora
sudo dnf install -y ffmpeg

# Arch Linux
sudo pacman -S ffmpeg

Note: You may need to manually set the FFmpeg path in Jellyfin's dashboard under Dashboard → Playback → FFmpeg path.

System Dependencies (Linux)

Jellyfin requires certain system libraries to be installed:

Debian/Ubuntu-based systems:

sudo apt-get update
sudo apt-get install -y \
    libfontconfig1 \
    libfreetype6 \
    libssl3 \
    libicu-dev

Note: See the FFmpeg Requirements section above for installing jellyfin-ffmpeg.

RHEL/CentOS/Fedora-based systems:

sudo dnf install -y \
    fontconfig \
    freetype \
    openssl \
    libicu

Note: See the FFmpeg Requirements section above for installing FFmpeg.

Arch Linux:

sudo pacman -S fontconfig freetype2 openssl icu

Note: See the FFmpeg Requirements section above for installing FFmpeg.

Note: The libfontconfig1 library is required for SkiaSharp (image processing). Without it, Jellyfin will fail to start with:

libfontconfig.so.1: cannot open shared object file: No such file or directory

PostgreSQL Requirements

  • PostgreSQL 12 or higher (tested with PostgreSQL 18.3)
  • psql client tools (for automatic schema initialization)
  • Network access to PostgreSQL server (if using remote database)

Install PostgreSQL client tools:

Debian/Ubuntu:

sudo apt-get install -y postgresql-client

RHEL/CentOS/Fedora:

sudo dnf install -y postgresql

Verify psql is available:

psql --version

Database Configuration

Create or edit config/database.xml in your Jellyfin data directory:

<?xml version="1.0" encoding="utf-8"?>
<DatabaseConfigurationOptions>
  <DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
  <LockingBehavior>NoLock</LockingBehavior>
  
  <CustomProviderOptions>
    <PluginName>Jellyfin-PostgreSQL</PluginName>
    <PluginAssembly>Jellyfin.Database.Providers.Postgres</PluginAssembly>
    
    <!-- Connection string with all parameters -->
    <ConnectionString>Host=192.168.1.100;Port=5432;Database=jellyfin;Username=jellyfin;Password=your_password_here</ConnectionString>
  </CustomProviderOptions>
  
  <!-- Optional: Backup configuration (works for both local and remote databases) -->
  <BackupOptions>
    <PgDumpPath>pg_dump</PgDumpPath>
    <PgRestorePath>pg_restore</PgRestorePath>
    <BackupFormat>custom</BackupFormat>
    <IncludeBlobs>true</IncludeBlobs>
    <CompressionLevel>6</CompressionLevel>
    <TimeoutSeconds>1800</TimeoutSeconds>
    <VerboseOutput>true</VerboseOutput>
  </BackupOptions>
</DatabaseConfigurationOptions>

Option 2: Using Individual Options

<?xml version="1.0" encoding="utf-8"?>
<DatabaseConfigurationOptions>
  <DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
  
  <CustomProviderOptions>
    <PluginName>Jellyfin-PostgreSQL</PluginName>
    <PluginAssembly>Jellyfin.Database.Providers.Postgres</PluginAssembly>
    
    <Options>
      <CustomDatabaseOption>
        <Key>Host</Key>
        <Value>192.168.1.100</Value>
      </CustomDatabaseOption>
      
      <CustomDatabaseOption>
        <Key>Port</Key>
        <Value>5432</Value>
      </CustomDatabaseOption>
      
      <CustomDatabaseOption>
        <Key>Database</Key>
        <Value>jellyfin</Value>
      </CustomDatabaseOption>
      
      <CustomDatabaseOption>
        <Key>Username</Key>
        <Value>jellyfin</Value>
      </CustomDatabaseOption>
      
      <CustomDatabaseOption>
        <Key>Password</Key>
        <Value>your_password_here</Value>
      </CustomDatabaseOption>
    </Options>
  </CustomProviderOptions>
</DatabaseConfigurationOptions>

Option 3: Hybrid (ConnectionString + Overrides)

Individual options take precedence over ConnectionString:

<CustomProviderOptions>
  <!-- Base connection -->
  <ConnectionString>Host=192.168.1.100;Port=5432;Database=jellyfin;Username=jellyfin</ConnectionString>
  
  <!-- Override just the password -->
  <Options>
    <CustomDatabaseOption>
      <Key>Password</Key>
      <Value>production_password</Value>
    </CustomDatabaseOption>
  </Options>
</CustomProviderOptions>

Database Initialization

Automatic Initialization

When Jellyfin starts with an empty database:

  1. Database Check: Checks if the database exists (creates if missing)
  2. Table Check: Checks if users.Users table exists
  3. Auto-Initialize: If tables don't exist, automatically runs sql/schema_init/create_database_schema.sql via psql
  4. Schema Verification: Verifies all required schemas and tables are present

Requirements for automatic initialization:

  • psql command must be in system PATH
  • Database must exist (created automatically or manually)
  • SQL script must be deployed: sql/schema_init/create_database_schema.sql

Manual Initialization

If psql is not available or automatic initialization fails:

# Create database first
createdb -U postgres jellyfin

# Run schema creation script
psql -U postgres -d jellyfin -f /path/to/jellyfin/sql/schema_init/create_database_schema.sql

Startup Logs

Successful Startup (Empty Database):

[INF] PostgreSQL connection: Host="192.168.1.100", Port=5432, Database="jellyfin", ...
[INF] Database tables not found (users.Users table missing). Initializing from SQL script...
[INF] Found schema script at: .../sql/schema_init/create_database_schema.sql
[INF] Executing create_database_schema.sql (this may take several minutes)...
[INF] Executing via psql: psql -h 192.168.1.100 -p 5432 -U jellyfin -d jellyfin -f "..."
[INF] ✅ Successfully initialized database from SQL script via psql
[INF] Database is ready. You can now start Jellyfin.
[DBG] Schema 'users' contains 4 tables
[DBG] Schema 'library' contains 45 tables
[DBG] Schema 'activitylog' contains 1 tables
[INF] ✅ Database schema verification complete
[INF] There are 0 migrations for stage CoreInitialisation
[INF] There are 24 migrations for stage AppInitialisation

Successful Startup (Existing Database):

[INF] PostgreSQL connection: Host="192.168.1.100", Port=5432, Database="jellyfin", ...
[INF] Database tables exist (users.Users table found)
[DBG] Schema 'users' contains 4 tables
[DBG] Schema 'library' contains 45 tables
[INF] ✅ Database schema verification complete

Troubleshooting

Error: libfontconfig.so.1: cannot open shared object file

Cause: Missing system dependency

Solution:

# Debian/Ubuntu
sudo apt-get install -y libfontconfig1

# RHEL/Fedora
sudo dnf install -y fontconfig

Error: psql command not found

Cause: PostgreSQL client tools not installed

Solution:

# Debian/Ubuntu
sudo apt-get install -y postgresql-client

# RHEL/Fedora
sudo dnf install -y postgresql

Error: Failed to connect to 127.0.0.1:5432

Cause: Configuration not loading correctly (using default localhost)

Solution:

  • Verify database.xml is in the correct location (/var/lib/jellyfin/config/database.xml on Linux)
  • Check that ConnectionString or individual Options are properly configured
  • Ensure Host is set to your remote server IP/hostname

Error: database "jellyfin" does not exist

Cause: Database wasn't created automatically (rare)

Solution:

# Create database manually
createdb -U postgres -h your-server jellyfin

# Grant privileges
psql -U postgres -h your-server -c "GRANT ALL PRIVILEGES ON DATABASE jellyfin TO jellyfin;"

# Restart Jellyfin (it will create tables automatically)

Architecture

Database Schema

  • activitylog - Activity log entries
  • authentication - API keys, devices, device options
  • displaypreferences - User display preferences
  • library - Media library data (BaseItems, metadata, etc.)
  • users - User accounts, permissions, preferences

Migration System

Entity Framework migrations are DISABLED for .NET 11 preview. Schema changes are managed via SQL scripts:

  • Core migrations: Disabled (no database structure changes via EF)
  • Application migrations: Enabled (configuration and data migrations only)

Why: EF migrations in preview builds can cause schema inconsistencies. SQL scripts provide reliable schema management.


Backup and Restore

Automatic Backups (via pg_dump)

Configured in database.xml:

<BackupOptions>
  <PgDumpPath>pg_dump</PgDumpPath>
  <BackupFormat>custom</BackupFormat>
  <CompressionLevel>6</CompressionLevel>
</BackupOptions>

Works for both local and remote databases!

Manual Backup

# Backup to custom format (compressed)
pg_dump -h your-server -U jellyfin -d jellyfin -Fc -f jellyfin_backup.dump

# Backup to SQL format
pg_dump -h your-server -U jellyfin -d jellyfin -f jellyfin_backup.sql

Manual Restore

# Restore from custom format
pg_restore -h your-server -U jellyfin -d jellyfin jellyfin_backup.dump

# Restore from SQL format
psql -h your-server -U jellyfin -d jellyfin -f jellyfin_backup.sql

Troubleshooting Connection Issues

Error: 57P01: terminating connection due to administrator command

Cause: PostgreSQL server forcibly terminated the connection during an operation

Common reasons:

  • PostgreSQL server restart or reload
  • Connection timeout (statement_timeout, idle_in_transaction_session_timeout)
  • Manual connection termination via pg_terminate_backend()
  • Network instability or firewall issues
  • Resource limits exceeded (max_connections, memory pressure)

Solutions:

1. Configure Automatic Retry (Already Enabled)

Jellyfin now includes automatic retry logic for transient failures:

  • Max retries: 3 attempts
  • Max delay: 5 seconds between retries
  • Retryable errors: Includes 57P01 (connection termination)

2. Increase PostgreSQL Timeouts

Edit PostgreSQL configuration (/etc/postgresql/*/main/postgresql.conf):

# Increase statement timeout
statement_timeout = 300000              # 5 minutes (in milliseconds)

# Increase idle transaction timeout
idle_in_transaction_session_timeout = 600000  # 10 minutes

# Enable TCP keepalives (prevent network timeouts)
tcp_keepalives_idle = 60                # seconds
tcp_keepalives_interval = 10            # seconds
tcp_keepalives_count = 6

Reload PostgreSQL:

sudo systemctl reload postgresql
# OR
psql -U postgres -c "SELECT pg_reload_conf();"

3. Optimize Connection String

Add keepalive and timeout parameters to your connection string:

<ConnectionString>Host=192.168.129.253;Port=5432;Database=jellyfin;Username=jellyfin;Password=yourpass;Pooling=True;Minimum Pool Size=0;Maximum Pool Size=50;Connection Idle Lifetime=300;Connection Pruning Interval=10;Timeout=30;Command Timeout=300;Keepalive=60</ConnectionString>

Key parameters:

  • Timeout=30 - Connection establishment timeout (30 seconds)
  • Command Timeout=300 - Query execution timeout (5 minutes)
  • Keepalive=60 - TCP keepalive interval (60 seconds)
  • Connection Idle Lifetime=300 - Close idle connections after 5 minutes
  • Connection Pruning Interval=10 - Check for stale connections every 10 seconds

4. Check PostgreSQL Logs

On your PostgreSQL server:

# View recent logs
sudo tail -f /var/log/postgresql/postgresql-*.log

# Or check systemd journal
sudo journalctl -u postgresql -n 100 --no-pager

Look for:

  • received fast shutdown request
  • terminating connection
  • too many connections
  • out of memory

5. Monitor Active Connections

-- Check current connections
SELECT 
    datname, 
    usename, 
    application_name,
    state,
    state_change
FROM pg_stat_activity
WHERE datname = 'jellyfin'
ORDER BY state_change DESC;

-- Check connection limits
SELECT 
    (SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max_connections,
    (SELECT COUNT(*) FROM pg_stat_activity) AS current_connections,
    (SELECT COUNT(*) FROM pg_stat_activity WHERE datname = 'jellyfin') AS jellyfin_connections;

Building from Source

# Clone repository
git clone https://github.com/yourusername/jellyfin.git
cd jellyfin

# Checkout the upgrade branch
git checkout upgrade-to-NET11

# Build
dotnet build

# Run
cd Jellyfin.Server
dotnet run

Contributing

This is a development/preview branch. For production use, please use the official Jellyfin releases.

License

GNU General Public License v2.0 (same as Jellyfin)


Credits

Based on Jellyfin with PostgreSQL support and .NET 11 compatibility.