SQL query that flattens many-to-one relationships
Don't LEFT JOIN unless you really need to
In a comment I asked:

Is there a specific reason you are using LEFT JOIN so much? Do you expect products to not have references in those tables a lot? LEFT JOIN are quite expensive and should be used only when needed – Phrancis

To which you responded:

I don't expect it to happen a lot, but I do expect it to happen. In particular, there are products with no options. But there aren't any products with no categories. – 4castle

That being said, you probably ought to build into your script some checks for that. In plain English, something like this might make sense. You can use if/else blocks to make it work.

Check with only a left join on your options. This should cover a large amount of cases, based on your response.

Should that return no rows for an existing product, then try with more left joins to see if something else might be missing.

Should that still return no rows, or invalid data, throw an error.



Aliases
There are a few points from your code that I think can be improved. For instance FROM product p is not a good alias (consider the other aliases as well), as aliases should at least give a hint as to what they are referring to, and p really doesn't. FROM product AS prod would be better in this case.
Also notice the addition of AS keyword which is good practice. It's less of a big deal with table aliases, but it can cause issues in particular with column aliases if it is missing, so it's really best to just include it.