You can have a logic in it for example if expired today, send them a friendly reminder over email, and allow that for 2/3 days. If no action taken by the user then disable their account. For example a datetime field expired_at if set to a value instead of null it means that the user has no active subscription.
@smeunus I second @nakov on the logic for periodic processing (CRON). It is also wise to keep all the use- and edgecases in mind. For example:
Is it possible to switch between plans?
Is it possible to have multiple plans at once?
Is the functionality for auto-renewal required? If yes, what is the logic behind this?
Should a user have the option to pause/restart it's subscription?
On a second note: with this kind of periodic processing, a form of security in your code would be wise to counter the event of data being altered by two (or more) executions of your code (and therefore malformed). For example, this can be accomplished by a processing column in your DB which will be filled with a timestamp (UUID4 is my preference) when the code is executed.
If the job would run only one time at night, this shouldn't be too much of a problem. Nonetheless, this can come in handy at some point during developing.