Quartz.NETQuartz.NET
Home
Features
Discussions
NuGet
GitHub
Home
Features
Discussions
NuGet
GitHub
  • Getting Started

    • Quartz 3 Quick Start
    • Tutorial
      • Using Quartz
      • Library Overview
      • Jobs And Triggers
      • More About Jobs
      • More About Triggers
      • Execution Groups
      • Node Affinity (Preferred Node)
      • Simple Triggers
      • Cron Triggers
      • RecurrenceTrigger
      • Trigger and Job Listeners
      • Scheduler Listeners
      • Job Stores
      • Tuning the Scheduler
      • Configuration, Resource Usage and SchedulerFactory
      • Advanced (Enterprise) Features
    • Configuration Reference
    • JSON Configuration
    • Frequently Asked Questions
    • Best Practices
    • Troubleshooting
    • API Documentation
    • Database Schema
    • Database Schema Changes
    • Migration Guide
    • Miscellaneous Features
  • How To's

    • One-Off Job
    • Multiple Triggers
    • Job Template
    • Using the CronTrigger
    • Rescheduling Jobs
  • Packages

    • Quartz Core Additions

      • Dashboard
      • Jobs
      • Serialization (System.Text.Json)
      • Serialization (Newtonsoft Json.NET)
      • Plugins
    • Integrations

      • ASP.NET Core Integration
      • Hosted Services Integration
      • Microsoft DI Integration
      • Multiple Schedulers with Microsoft DI
      • OpenTelemetry Integration
      • OpenTracing Integration
      • Redis Lock Handler
      • TimeZoneConverter Integration
    • 3rd Party Plugins for Quartz
  • Unreleased Releases

    • Quartz 4.x
      • Quartz 4 Quick Start
      • Tutorial
        • Using Quartz
        • Jobs And Triggers
        • More About Jobs & JobDetails
        • More About Triggers
        • Execution Groups
        • Node Affinity (Preferred Node)
        • Simple Triggers
        • Cron Triggers
        • RecurrenceTrigger
        • Trigger and Job Listeners
        • Scheduler Listeners
        • Job Stores
        • Configuration, Resource Usage and SchedulerFactory
        • Advanced (Enterprise) Features
        • Miscellaneous Features
        • CronTrigger Tutorial
      • Configuration Reference
      • JSON Configuration
      • Database Schema
      • Database Schema Changes
      • Migration Guide
      • Troubleshooting
      • API Documentation
      • How To's

        • One-Off Job
        • Multiple Triggers
        • Job Template
        • Using the CronTrigger
      • Packages

        • Quartz Core Additions

          • Dashboard
          • Jobs
          • Serialization (System.Text.Json)
          • JSON Serialization
          • Plugins
        • Integrations

          • ASP.NET Core Integration
          • HTTP API
          • Hosted Services Integration
          • Microsoft DI Integration
          • Multiple Schedulers with Microsoft DI
          • OpenTelemetry Integration
          • OpenTracing Integration
          • Redis Lock Handler
          • TimeZoneConverter Integration
        • 3rd Party Plugins for Quartz
  • Old Releases

    • Quartz 2.x
      • Quartz 2 Quick Start
      • Tutorial
        • Lesson 1: Using Quartz
        • Lesson 2: Jobs And Triggers
        • Lesson 3: More About Jobs & JobDetails
        • Lesson 4: More About Triggers
        • Lesson 5: SimpleTrigger
        • Lesson 6: CronTrigger
        • Lesson 7: TriggerListeners and JobListeners
        • Lesson 8: SchedulerListeners
        • Lesson 9: JobStores
        • Lesson 10: Configuration, Resource Usage and SchedulerFactory
        • Lesson 11: Advanced (Enterprise) Features
        • Lesson 12: Miscellaneous Features of Quartz
        • CronTrigger Tutorial
      • Configuration Reference
      • Migration Guide
      • API Documentation
    • Quartz 1.x
      • Tutorial
        • Lesson 1: Using Quartz
        • Lesson 2: Jobs And Triggers
        • Lesson 3: More About Jobs & JobDetails
        • Lesson 4: More About Triggers
        • Lesson 5: SimpleTrigger
        • Lesson 6: CronTrigger
        • Lesson 7: TriggerListeners and JobListeners
        • Lesson 8: SchedulerListeners
        • Lesson 9: JobStores
        • Lesson 10: Configuration, Resource Usage and SchedulerFactory
        • Lesson 11: Advanced (Enterprise) Features
        • Lesson 12: Miscellaneous Features of Quartz
      • API Documentation
  • License

Every Quartz.NET release that changed the database schema, in order, with the migration to run and what happens if you skip it.

Quartz.NET never creates or migrates your schema automatically. Read from your current version down to your target version and apply what each section lists.

Warning

Always run migration scripts in a test environment against a copy of your production database first.

How to use this page

Scripts live in database/migrations/, one folder per version. Inside each folder, run the file whose suffix matches your database — _sqlServer, _postgres, _mysql_innodb, _oracle, _sqlite, _firebird. Each file is directly runnable with no editing.

Apply every version between where you are and where you are going, in ascending order, and do not skip one. Some migrations are optional — you can defer them — but they are cumulative, not alternatives. Skipping 3.17 and later running 3.19 leaves you without the 3.17 column; nothing goes back and adds it.

Everything except the SQL Server 1.0→2.0 script checks before it acts, so re-running a migration is a no-op and a half-applied migration is safe to re-run. SQLite ADD COLUMN is the one exception: SQLite has no conditional DDL, so those statements fail on a second run.

A fresh install needs none of this. The scripts in database/tables/ already create everything below.

What do I need?

Coming fromGoing toWhat to run
1.xany 2.x/3.x2.0, 2.2, 2.6, then 3.x as below
2.0 / 2.13.x2.2, 2.6, 3.0, then the optional 3.x ones
2.2–2.53.x2.6, 3.0, then the optional 3.x ones
2.63.x3.0, then the optional 3.x ones
3.0–3.16latest 3.x3.17, 3.18, 3.19, 3.20 — all optional
any 3.x4.x4.0 — mandatory, and it folds in everything from 3.17 onward

Upgrading to 4.x is mandatory {#v4-mandatory}

This is the one migration you cannot defer.

Quartz.NET 3.x probes for MISFIRE_ORIG_FIRE_TIME, EXECUTION_GROUP, PREFERRED_NODE and PREFERRED_NODE_AUTO when the scheduler starts. If a column is missing it logs a warning and turns the corresponding feature off — which is why those migrations are optional on 3.x.

4.x removed those probes and assumes all four columns exist. A 3.x database that never ran the optional migrations will not work against 4.x until 4.0 has been applied.


2.0 {#v2-0}

Required when upgrading from 1.x. Nothing later applies until this has run.

The 1.x → 2.x schema overhaul: the listener tables are dropped, varchar(1) flag columns become real bit columns, IS_STATEFUL is replaced by IS_NONCONCURRENT and IS_UPDATE_DATA, and SCHED_NAME is introduced across every table with the primary keys and indexes rebuilt around it.

  • Script: migrations/2.0/schema_10_to_20_upgrade_sqlServer.sql
  • SQL Server only — it is a sample, and needs adapting for other databases.
  • Not idempotent. It drops and recreates objects unconditionally, so it fails on a partially-migrated database. Run it once, on a restorable copy.

Warning

The script defaults SCHED_NAME to TestScheduler. If you have existing data, change it to match your quartz.scheduler.instanceName.

2.2 {#v2-2}

Required when upgrading from 2.0 or 2.1.

Adds SCHED_TIME to QRTZ_FIRED_TRIGGERS so recovery jobs can see both the scheduled and the actual fire time (#113).

  • Scripts: migrations/2.2/ — all databases

The column is NOT NULL with no default, so the ALTER fails on a table that already holds rows. QRTZ_FIRED_TRIGGERS only ever holds in-flight entries, so stop the scheduler and clear it first:

DELETE FROM QRTZ_FIRED_TRIGGERS;

2.6 {#v2-6}

Required when upgrading from 2.5 or earlier.

Adds TIME_ZONE_ID to QRTZ_SIMPROP_TRIGGERS and QRTZ_CRON_TRIGGERS, so a trigger's time zone survives a restart (#136).

  • Scripts: migrations/2.6/ — all databases

Tips

Older copies of this migration only altered QRTZ_SIMPROP_TRIGGERS. QRTZ_CRON_TRIGGERS needs the column too (#1985) — if you upgraded 2.5→2.6 some time ago, check that both tables have it.

3.0 {#v3-0}

Required when upgrading a SQL Server database from 2.6.

Converts the deprecated IMAGE columns to VARBINARY(MAX) (#291): QRTZ_CALENDARS.CALENDAR, QRTZ_JOB_DETAILS.JOB_DATA, QRTZ_BLOB_TRIGGERS.BLOB_DATA and QRTZ_TRIGGERS.JOB_DATA.

  • Script: migrations/3.0/schema_26_to_30_upgrade_sqlServer.sql
  • SQL Server only — no other dialect ever used IMAGE.

3.17 {#v3-17}

Optional on 3.x. Required on 4.x.

Adds MISFIRE_ORIG_FIRE_TIME to QRTZ_TRIGGERS (#2899). It stores the original scheduled fire time before misfire handling overwrites it.

  • Scripts: migrations/3.17/ — all databases

If you skip it: AdoJobStore keeps working, but ScheduledFireTimeUtc equals FireTimeUtc for misfired triggers under the "fire now" misfire policies, instead of reporting the time the trigger was supposed to fire. RAMJobStore is unaffected.

-- SQL Server
ALTER TABLE QRTZ_TRIGGERS ADD MISFIRE_ORIG_FIRE_TIME bigint NULL;

3.18 {#v3-18}

Optional on 3.x. Required on 4.x.

Adds EXECUTION_GROUP to QRTZ_TRIGGERS and QRTZ_FIRED_TRIGGERS (#3004), carrying the execution group tag that per-node thread limits are enforced against. Both tables need it.

  • Scripts: migrations/3.18/ — all databases

If you skip it: execution groups still work, but the limit is applied by in-memory filtering after acquisition rather than in the acquire query — so a node acquires triggers it then has to put back.

-- SQL Server
ALTER TABLE QRTZ_TRIGGERS ADD EXECUTION_GROUP nvarchar(200) NULL;
ALTER TABLE QRTZ_FIRED_TRIGGERS ADD EXECUTION_GROUP nvarchar(200) NULL;

3.19 {#v3-19}

Optional on 3.x. Required on 4.x.

Adds PREFERRED_NODE and PREFERRED_NODE_AUTO to QRTZ_TRIGGERS (#3013, #3144), which back node affinity.

  • Scripts: migrations/3.19/ — all databases

Both columns must be added together. Quartz probes for both and only enables node affinity when both are present, so adding just one leaves the feature off.

If you skip it: node affinity is unavailable. The scheduler logs a warning at startup and otherwise behaves exactly as it did in 3.18.

-- SQL Server
ALTER TABLE QRTZ_TRIGGERS ADD PREFERRED_NODE nvarchar(200) NULL;
ALTER TABLE QRTZ_TRIGGERS ADD PREFERRED_NODE_AUTO bit NOT NULL DEFAULT 0;

3.20 {#v3-20}

Optional, performance only.

Realigns the index set with the statements AdoJobStore actually issues (#3203).

  • Scripts: migrations/3.20/ — all databases

Every Quartz statement filters SCHED_NAME first, yet several shipped indexes did not lead with it and so could not serve a single-scheduler lookup at all — most visibly on PostgreSQL, where 9 of 11 indexes were affected and IDX_QRTZ_T_NFT_ST had its columns in the wrong order. Indexes that are a leftmost prefix of a wider one, or that no statement can drive a scan from, are dropped.

SQLite previously shipped no secondary indexes whatsoever, so every acquire poll was a full table scan; this adds them.

If you skip it: everything works, just with more index maintenance on writes and worse plans on reads. A database created from the current tables/ script already matches and needs nothing here.

Tips

On a busy PostgreSQL database use CREATE INDEX CONCURRENTLY / DROP INDEX CONCURRENTLY. Neither can run inside a transaction block, so run those statements one at a time.

4.0 {#v4-0}

Mandatory. See above for why.

  • Scripts: migrations/4.0/ — all databases

Applies everything from 3.17, 3.18, 3.19 and 3.20, plus the 4.x index shape, in one pass. Run it whether or not you applied the optional migrations — every statement is guarded, so it is safe on a partially-migrated database.

Sections, in order:

#ChangeStatus
1MISFIRE_ORIG_FIRE_TIME columnrequired
2EXECUTION_GROUP columnsrequired
3PREFERRED_NODE / PREFERRED_NODE_AUTO columnsrequired
4Index set aligned with the 4.x schemaoptional

Run them in order — the drops in section 4 assume the creates above them have already succeeded.

The 4.x listing queries page with ORDER BY JOB_GROUP, JOB_NAME and ORDER BY TRIGGER_GROUP, TRIGGER_NAME, and the primary keys are name-before-group, so section 4 adds IDX_QRTZ_J_G_N and IDX_QRTZ_T_G_N to serve those ordered scans. Without them each page is a scan plus a sort.

Node affinity needs no data migration: 3.x and 4.x store pins identically.

See also

  • database/README.md — the same table, in the repository
  • Database Schema — what each table holds
  • Migration Guide — the rest of the 3.x → 4.x upgrade
Help us by improving this page!
Last Updated: 8/1/26, 4:21 AM
Contributors: Marko Lahma, Claude Fable 5, Claude Opus 5 (1M context)
Prev
Database Schema
Next
Migration Guide