Is my JWT refresh plan secure?

Acceptably secure within the realm of what?

You have described the basic flow for all bearer tokens. They who bear the token have the power. You do have a condition where you check if the token has been revoked, but that will mean the token is valid until they expire or are revoked. This is fundamentally the same as checking if the user is valid in the database, but you're replacing user with device + JWT. That's fine, but it's not much of a performance gain.

Other systems use two JWT's (or a JWT and an opaque token). The first JWT is your access token used mostly like you describe, but you don't check for revocation. This token is very short-lived -- maybe 20 min -> 1h, and then you have your refresh token which lives considerably longer. When your access token expires you send the refresh token and if the refresh token is still valid you issue a new access token. If the refresh token is expired you can force authentication again, or just issue a new access and refresh token.

The value here is that you only need to validate the refresh token against the database, and you only need to do that when the access token expires. When the user marks the refresh token as revoked then the refresh token doesn't get the attacker a new access token.

The trade off is that you don't query into the database as often, but the attacker can do whatever they want as long as the access token is valid. This is mitigated with using a very short lived token (its a game of odds). Whether this is an accepted risk is totally up to you. We don't dictate whether you should accept the risk. :)